package com.brillilab.service.logic.kit;

import com.brillilab.common.constant.ClientTypeEnum;
import com.brillilab.common.constant.ResultEnum;
import com.brillilab.common.entity.PageVo;
import com.brillilab.common.exceptions.BrillilabException;
import com.brillilab.common.rocketmq.OnsMessageEnum;
import com.brillilab.common.rocketmq.OnsMessageVo;
import com.brillilab.common.rocketmq.OnsProducer;
import com.brillilab.common.rocketmq.OnsProperties;
import com.brillilab.common.utils.DateUtil;
import com.brillilab.common.utils.MyBeanUtils;
import com.brillilab.domain.enums.common.BoolEnum;
import com.brillilab.domain.enums.experiment.ExperimentBillSourceEnum;
import com.brillilab.domain.enums.experiment.UsageOperationEnum;
import com.brillilab.domain.enums.hardware.LockOperationEnum;
import com.brillilab.domain.enums.hardware.LockStateEnum;
import com.brillilab.domain.enums.inventory.InventoryRecordEnum;
import com.brillilab.domain.enums.kit.KitEnum;
import com.brillilab.domain.enums.kit.KitTakeType;
import com.brillilab.domain.enums.kit.KitUsageEnum;
import com.brillilab.domain.enums.lab.LabMemberPowerEnum;
import com.brillilab.domain.enums.lab.UserEnum;
import com.brillilab.domain.pa.experiments.PrintPreviewGet;
import com.brillilab.domain.po.experiments.*;
import com.brillilab.domain.po.hardware.HardWareOperateRecord;
import com.brillilab.domain.po.hardware.LockOperation;
import com.brillilab.domain.po.inventory.ReagentInventory;
import com.brillilab.domain.po.kit.*;
import com.brillilab.domain.po.lab.Lab;
import com.brillilab.domain.po.lab.LabMemberPower;
import com.brillilab.domain.po.space.Box;
import com.brillilab.domain.po.user.Users;
import com.brillilab.domain.vo.experiments.ExperimentKitUsageListVo;
import com.brillilab.domain.vo.experiments.ExperimentKitUsageStepVo;
import com.brillilab.domain.vo.experiments.ExperimentKitUsageVo;
import com.brillilab.domain.vo.kit.*;
import com.brillilab.domain.vo.lock.ItemLock;
import com.brillilab.domain.vo.print.KitUsageDevicePrintVo;
import com.brillilab.domain.vo.print.KitUsageItemPrintVo;
import com.brillilab.domain.vo.space.BoxPositionData;
import com.brillilab.domain.vo.user.UserInfoVo;
import com.brillilab.service.constant.JobConstants;
import com.brillilab.service.core.experiments.*;
import com.brillilab.service.core.hardware.IHardwareOperateRecordService;
import com.brillilab.service.core.hardware.ILockOperationService;
import com.brillilab.service.core.inventory.IInventoryRecordService;
import com.brillilab.service.core.inventory.IReagentInventoryService;
import com.brillilab.service.core.kit.*;
import com.brillilab.service.core.lab.ILabMemberPowerService;
import com.brillilab.service.core.lab.ILabMemberService;
import com.brillilab.service.core.lab.ILabService;
import com.brillilab.service.core.space.IBoxService;
import com.brillilab.service.core.space.IDeviceService;
import com.brillilab.service.core.system.IDictService;
import com.brillilab.service.core.user.IUsersService;
import com.brillilab.service.job.kit.KitUsageJob;
import com.brillilab.service.logic.experiments.ExperimentLogic;
import com.brillilab.service.logic.inventory.ReagentInventoryLogic;
import com.brillilab.service.logic.space.PanelLogic;
import com.brillilab.service.quartz.BrillQuartzScheduler;
import com.brillilab.service.utils.QuartzUtils;
import org.apache.commons.lang.StringUtils;
import org.quartz.JobDataMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * 取用/待归还清单
 *
 * @author wmh
 */
@Service
@Transactional
public class KitUsageLogic {

    @Resource
    private IUsersService usersService;
    @Resource
    private ILabMemberPowerService labMemberPowerService;
    @Resource
    private ILabService labService;
    @Resource
    private ILabMemberService labMemberService;
    @Resource
    private IKitUsageService kitUsageService;
    @Resource
    private IReagentInventoryService reagentInventoryService;
    @Resource
    private IKitService kitService;
    @Resource
    private IDictService dictService;
    @Resource
    private IKitSpecService kitSpecService;
    @Resource
    private IkitRegularUsageGroupService regularUsageGroupService;
    @Resource
    private IReagentTypeService reagentTypeService;
    @Resource
    private IReagentService reagentService;
    @Resource
    private ReagentLogic reagentLogic;
    @Resource
    private ReagentInventoryLogic reagentInventoryLogic;
    @Resource
    private IInventoryRecordService inventoryRecordService;
    @Resource
    private IDeviceService deviceService;
    @Resource
    private IBoxService boxService;
    @Resource
    private BrillQuartzScheduler scheduler;

    @Resource
    private PanelLogic panelLogic;
    @Resource
    private OnsProperties onsProperties;
    @Resource
    private OnsProducer onsProducer;

    @Resource
    private IExperimentStepService experimentStepService;
    @Resource
    private IExperimentService experimentService;
    @Resource
    private IExperimentPhaseService experimentPhaseService;
    @Resource
    private IExperimentStepReagentService experimentStepReagentService;
    @Resource
    private IExperimentBillService experimentBillService;
    @Autowired
    private ExperimentLogic experimentLogic;

    @Resource
    private ILockOperationService lockOperationService;
    @Resource
    private IHardwareOperateRecordService hardwareOperateRecordService;

    /**
     * 试剂成分加入取用清单
     *
     * @param userInfo
     * @param kitUsageAdds
     */
    public void addInventoryToTakeList(UserInfoVo userInfo, List<KitUsageAdd> kitUsageAdds) {

        Assert.isTrue(userInfo != null && !CollectionUtils.isEmpty(kitUsageAdds), "参数缺失！");

        List<LabMemberPower> labMemberPowers = labMemberPowerService.selectList(userInfo.getLabId(), userInfo.getLabMemberId());
        Lab lab = labService.selectById(userInfo.getLabId());

        List<KitUsage> kitUsages = new ArrayList<>();
        List<KitUsage> kitUsageUpdates = new ArrayList<>();
        //inventories
        List<Long> inventoryIds = kitUsageAdds.stream().map(KitUsageAdd::getInventoryId).distinct().collect(Collectors.toList());
        List<ReagentInventory> inventories = reagentInventoryService.selectList(inventoryIds, BoolEnum.FALSE.getValue());
        //kits
        List<Long> kitIds = inventories.stream().map(ReagentInventory::getKitId).distinct().collect(Collectors.toList());
        List<Kit> kits = kitService.selectByIds(kitIds);
        //firstReagentTypeMap
        List<Long> reagentTypeIds = inventories.stream().map(ReagentInventory::getReagentTypeId).distinct().collect(Collectors.toList());
        Map<Long, Long> firstReagentTypeMap = reagentTypeService.selectFirstReagentTypeMap(reagentTypeIds);
        //exists
        List<KitUsage> exists = kitUsageService.selectList(userInfo.getLabId(), userInfo.getLabMemberId(), KitUsageEnum.State.TAKE.getValue())
                .stream().filter(e -> e.getExperimentId() == null).collect(Collectors.toList());

        Date updateTime = new Date();
        kitUsageAdds.forEach(kitUsageAdd -> {
            Assert.isTrue(kitUsageAdd.getInventoryId() != null && kitUsageAdd.getAmount() != null, "请求参数缺失！");

            Long inventoryId = kitUsageAdd.getInventoryId();
            BigDecimal amount = kitUsageAdd.getAmount();

            Assert.isTrue(amount.compareTo(BigDecimal.valueOf(0)) >= 0, "取用量不能为负值！");

            //获取取用试剂的库存ReagentInventory
            ReagentInventory reagentInventory = inventories.stream().filter(e -> e.getId().equals(inventoryId)).findFirst().orElse(null);
            if (reagentInventory != null) {
                assertInventoryBelongToLabAndLabMember(userInfo, reagentInventory, labMemberPowers, lab);

                //takeAmount值大于可用值，设置可用值
                amount = amount.compareTo(reagentInventory.getAmount()) > 0 ? reagentInventory.getAmount() : amount;
                //获取Kit
                Kit kit = kits.stream().filter(e -> e.getId().equals(reagentInventory.getKitId())).findFirst().orElse(null);
                Assert.notNull(kit, "试剂不存在！");
                //设置kitUsage相关属性

                KitUsage kitUsage = null;
                Optional<KitUsage> first = exists.stream().filter(e -> e.getInventoryId().equals(reagentInventory.getId())).findFirst();
                if (!first.isPresent()) {
                    kitUsage = new KitUsage();
                    kitUsage.setLabId(userInfo.getLabId());
                    kitUsage.setLabMemberId(userInfo.getLabMemberId());
                    kitUsage.setLabMemberName(userInfo.getName());
                    kitUsage.setKitId(reagentInventory.getKitId());
                    kitUsage.setReagentId(reagentInventory.getReagentId());
                    kitUsage.setFirstReagentTypeId(firstReagentTypeMap.get(reagentInventory.getReagentTypeId()));
                    kitUsage.setReagentName(reagentInventory.getReagentName());
                    kitUsage.setInventoryId(reagentInventory.getId());
                    kitUsage.setTakeAmount(amount);
                    kitUsage.setState(KitUsageEnum.State.TAKE.getValue());
                    kitUsage.setClassify(reagentInventory.getClassify());
                    kitUsages.add(kitUsage);
                } else {
                    kitUsage = first.get();
                    kitUsage.setTakeAmount(kitUsage.getTakeAmount().add(amount));
                    kitUsage.setUpdateTime(updateTime);
                    kitUsageUpdates.add(kitUsage);
                }

            }
        });
        if (kitUsages.size() > 0) {
            Integer rs = kitUsageService.saveTakeList(kitUsages);
            Assert.isTrue(rs == kitUsages.size(), "操作失败！");
        }
        if (kitUsageUpdates.size() > 0) {
            Integer rs2 = kitUsageService.updateBatch(kitUsageUpdates);
            Assert.isTrue(rs2 == kitUsageUpdates.size(), "操作失败！");
        }
    }

    /**
     * 试剂成分取用
     *
     * @param userInfo
     * @param kitUsageAdds
     */
    public void addInventoryToTakingList(UserInfoVo userInfo, List<KitUsageAdd> kitUsageAdds) {

        Assert.isTrue(userInfo != null && !CollectionUtils.isEmpty(kitUsageAdds), "参数缺失！");

        List<LabMemberPower> labMemberPowers = labMemberPowerService.selectList(userInfo.getLabId(), userInfo.getLabMemberId());
        Lab lab = labService.selectById(userInfo.getLabId());

        List<KitUsage> kitUsages = new ArrayList<>();
        Map<Long, ReagentInventory> inventoryMap = new HashMap<>();
        Map<Long, Kit> kitMap = new HashMap<>();
        Date usageTime = new Date();

        kitUsageAdds.forEach(kitUsageAdd -> {
            Assert.isTrue(kitUsageAdd.getInventoryId() != null && kitUsageAdd.getAmount() != null, "请求参数缺失！");

            Long inventoryId = kitUsageAdd.getInventoryId();
            BigDecimal amount = kitUsageAdd.getAmount();

            Assert.isTrue(amount.compareTo(BigDecimal.valueOf(0)) >= 0, "取用量不能为负值！");

            //获取取用试剂的库存ReagentInventory
            ReagentInventory reagentInventory = getReagentInventoryFromMap(inventoryMap, inventoryId);
            if (reagentInventory != null) {
                assertInventoryBelongToLabAndLabMember(userInfo, reagentInventory, labMemberPowers, lab);

                //takeAmount值大于可用值，设置可用值
                amount = amount.compareTo(reagentInventory.getAmount()) > 0 ? reagentInventory.getAmount() : amount;
                //获取Kit
                Kit kit = getKitFromMap(kitMap, reagentInventory.getKitId());
                Assert.notNull(kit, "试剂不存在！");
                //设置kitUsage相关属性
                KitUsage kitUsage = new KitUsage();
                kitUsage.setLabId(userInfo.getLabId());
                kitUsage.setLabMemberId(userInfo.getLabMemberId());
                kitUsage.setLabMemberName(userInfo.getName());
                kitUsage.setKitId(reagentInventory.getKitId());
                kitUsage.setReagentId(reagentInventory.getReagentId());
                kitUsage.setReagentName(reagentInventory.getReagentName());
                kitUsage.setInventoryId(reagentInventory.getId());
                kitUsage.setTakeAmount(amount);
                kitUsage.setUsageTime(usageTime);
                kitUsage.setClassify(reagentInventory.getClassify());
                kitUsage.setState(KitUsageEnum.State.TAKING.getValue());
                kitUsages.add(kitUsage);
            }
        });

        List<Long> kitUsageIds = kitUsages.stream().map(KitUsage::getId).distinct().collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(kitUsages)) {
            kitUsageService.saveTakeList(kitUsages);
            //推送开锁权限
            sendUnlockPowerListToAio(userInfo, kitUsages);
            //定时任务 24小时未开锁取用
            createTakingReturningJob(kitUsageIds, KitUsageEnum.State.TAKING.getValue(), 24 * 60 * 60 * 1000L);
        }

    }

    /**
     * 发送开锁权限到一体机
     *
     * @param userInfo
     * @param kitUsages
     */
    @Async
    public void sendUnlockPowerListToAio(UserInfoVo userInfo, List<KitUsage> kitUsages) {
        List<Long> kitUsageIds = kitUsages.stream().map(KitUsage::getId).collect(Collectors.toList());
        //使用websocket发送设备信息、取用信息给一体机
        List<DeviceUnlock> deviceUnlocks = kitUsageService.selectKitUsageDeviceUnLockList(kitUsageIds);
        Map<String, List<Long>> noAndIds = new HashMap<>();
        for (DeviceUnlock deviceUnlock : deviceUnlocks) {
            if (!noAndIds.containsKey(deviceUnlock.getDeviceNo())) {
                List<Long> deviceIds = new ArrayList<>();
                deviceIds.add(deviceUnlock.getDeviceId());
                noAndIds.put(deviceUnlock.getDeviceNo(), deviceIds);
            } else {
                List<Long> deviceIds = noAndIds.get(deviceUnlock.getDeviceNo());
                if (!deviceIds.contains(deviceUnlock.getDeviceId())) {
                    deviceIds.add(deviceUnlock.getDeviceId());
                }
            }
        }
        noAndIds.forEach((k, v) -> {
            Map<String, Object> data = new HashMap<>();
            data.put("labMemberId", userInfo.getLabMemberId());
            data.put("labMemberName", userInfo.getName());
            data.put("deviceIds", v);
            onsProducer.sendBroadcastMessage(onsProperties.webSocketAioTopic, new OnsMessageVo(OnsMessageEnum.UNLOCK_POWER, data, k));
        });
    }

    /**
     * 试剂成分加入未归还清单（废除）
     *
     * @param userInfo
     * @param kitUsageAdds
     */
    public void addInventoryToNotReturnList(UserInfoVo userInfo, List<KitUsageAdd> kitUsageAdds) {

        Assert.isTrue(userInfo != null && !CollectionUtils.isEmpty(kitUsageAdds), "参数缺失！");

        List<LabMemberPower> labMemberPowers = labMemberPowerService.selectList(userInfo.getLabId(), userInfo.getLabMemberId());
        Lab lab = labService.selectById(userInfo.getLabId());

        List<KitUsage> kitUsages = new ArrayList<>();
        List<ReagentInventory> updateList = new ArrayList<>();
        Map<Long, ReagentInventory> inventoryMap = new HashMap<>();
        Map<Long, Kit> kitMap = new HashMap<>();
        Date usageTime = new Date();

        kitUsageAdds.forEach(kitUsageAdd -> {
            Assert.isTrue(kitUsageAdd.getInventoryId() != null && kitUsageAdd.getAmount() != null, "请求参数缺失！");

            Long inventoryId = kitUsageAdd.getInventoryId();
            BigDecimal amount = kitUsageAdd.getAmount();

            Assert.isTrue(amount.compareTo(BigDecimal.valueOf(0)) >= 0, "取用量不能为负值！");

            //获取取用试剂的库存ReagentInventory
            ReagentInventory reagentInventory = getReagentInventoryFromMap(inventoryMap, inventoryId);
            if (reagentInventory != null) {
                assertInventoryBelongToLabAndLabMember(userInfo, reagentInventory, labMemberPowers, lab);

                //takeAmount值大于可用值，设置可用值
                amount = amount.compareTo(reagentInventory.getAmount()) > 0 ? reagentInventory.getAmount() : amount;
                //获取Kit
                Kit kit = getKitFromMap(kitMap, reagentInventory.getKitId());
                Assert.notNull(kit, "试剂不存在！");
                //设置kitUsage相关属性
                KitUsage kitUsage = new KitUsage();
                kitUsage.setLabId(userInfo.getLabId());
                kitUsage.setLabMemberId(userInfo.getLabMemberId());
                kitUsage.setLabMemberName(userInfo.getName());
                kitUsage.setKitId(reagentInventory.getKitId());
                kitUsage.setReagentId(reagentInventory.getReagentId());
                kitUsage.setReagentName(reagentInventory.getReagentName());
                kitUsage.setInventoryId(reagentInventory.getId());
                kitUsage.setTakeAmount(amount);
                kitUsage.setClassify(reagentInventory.getClassify());
                kitUsage.setUseAmount(amount);
                kitUsage.setUsageTime(usageTime);
                kitUsage.setState(KitUsageEnum.State.NOT_RETURN.getValue());
                kitUsages.add(kitUsage);
                //扣去Inventory可用量
                BigDecimal canUse = reagentInventory.getAmount();
                canUse = canUse.subtract(amount);
                reagentInventory.setAmount(canUse);
                reagentInventory.setInUse(1);
                updateList.add(reagentInventory);
            }
        });
        if (!CollectionUtils.isEmpty(kitUsages)) {
            Set<Long> kitIds = kitUsages.stream().map(KitUsage::getKitId).collect(Collectors.toSet());
            kitUsageService.saveTakeList(kitUsages);
            //取用记录
            inventoryRecordService.add(userInfo, new ArrayList<>(kitIds), InventoryRecordEnum.TAKE);
        }
        if (!CollectionUtils.isEmpty(updateList)) {
            reagentInventoryService.updateInventoryListAmount(updateList);
        }
    }

    /**
     * 清单
     *
     * @param labId
     * @param labMemberId
     * @return
     */
    public KitUsageListVo getManifestList(Long labId, Long labMemberId) {

        Assert.isTrue(labId != null && labMemberId != null, "参数缺失！");

        KitUsageListVo resultList = new KitUsageListVo();

        //生成KitUsageVoList
        List<KitUsage> result = kitUsageService.selectList(labId, labMemberId, KitUsageEnum.State.TAKE.getValue(), KitUsageEnum.State.NOT_RETURN.getValue(), KitUsageEnum.State.RETURNED.getValue());

        //分出一般清单，实验清单，常用清单
        //一般清单
        List<KitUsage> takeList = result.stream()
                .filter(kitUsageVo -> (kitUsageVo.getExperimentId() == null && kitUsageVo.getRegularUsageGroupId() == null) && (kitUsageVo.getState().equals(KitUsageEnum.State.TAKE.getValue()) || kitUsageVo.getState().equals(KitUsageEnum.State.NOT_RETURN.getValue())))
                .collect(Collectors.toList());
        List<Long> inventoryIds = takeList.stream().map(KitUsage::getInventoryId).distinct().collect(Collectors.toList());
        List<ReagentInventory> inventories = reagentInventoryService.selectList(inventoryIds, BoolEnum.FALSE.getValue());
        List<ExperimentKitUsageVo> take = new ArrayList<>();
        if (!CollectionUtils.isEmpty(takeList)) {
            take = getExperimentKitUsageVoList(inventories, takeList);
        }
        resultList.setTake(take);

        //实验清单
        List<KitUsage> experimentList = result.stream().filter(kitUsageVo -> kitUsageVo.getExperimentId() != null).collect(Collectors.toList());

        ArrayList<ExperimentKitUsageListVo> usageListVos = new ArrayList<>();
        if (!CollectionUtils.isEmpty(experimentList)) {
            //实验ID
            List<Long> experimentIds = experimentList.stream().map(KitUsage::getExperimentId).distinct().collect(Collectors.toList());

            List<Experiment> experiments = experimentService.selectByIdsAndNotEnd(experimentIds);

            List<ExperimentStep> stepList = experimentStepService.getExperimentStepList(experimentIds);

            experiments.forEach(experiment -> {
                List<KitUsage> exUsage = experimentList.stream().filter(e -> e.getExperimentId().equals(experiment.getId())).collect(Collectors.toList());
                List<ExperimentStep> oneExperiment = stepList.stream().filter(experimentStep -> experimentStep.getExperimentId().equals(experiment.getId())).collect(Collectors.toList());
                ExperimentKitUsageListVo experimentKitUsageListVo = this.getExperimentKitUsageListVo(experiment, oneExperiment, exUsage);
                usageListVos.add(experimentKitUsageListVo);
            });
        }
        resultList.setExperiment(usageListVos);

        return resultList;
    }

    /**
     * 取用清单列表
     *
     * @param labId
     * @param labMemberId
     * @return
     */
    public KitUsageTakeList getTakeList(Long labId, Long labMemberId) {

        Assert.isTrue(labId != null && labMemberId != null, "参数缺失！");

        KitUsageTakeList resultList = new KitUsageTakeList();

        //生成KitUsageVoList
        List<KitUsageVo> result = kitUsageService.getKitUsageVoList(labId, labMemberId, KitUsageEnum.State.TAKE.getValue());

        //试剂盒位置kitBoxIdList
        Map<Long, BoxPositionData> boxPositionData = getBoxPositionDataMap(result);

        //分出一般清单，实验清单，常用清单
        //一般清单
        List<KitUsageVo> takeList = result.stream().filter(kitUsageVo -> kitUsageVo.getExperimentId() == null && kitUsageVo.getRegularUsageGroupId() == null).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(takeList)) {
            List<KitTakeGroup> kitTakeGroups = new ArrayList<>();
            List<KitTakeDeviceList> kitTakeDeviceLists = getKitTakeLists(takeList, boxPositionData);
            KitTakeGroup kitTakeGroup = new KitTakeGroup();
            kitTakeGroup.setDevices(kitTakeDeviceLists);
            kitTakeGroups.add(kitTakeGroup);
            resultList.setTake(kitTakeGroups);
        }

        //实验清单
        List<KitUsageVo> experimentList = result.stream().filter(kitUsageVo -> kitUsageVo.getExperimentId() != null).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(experimentList)) {
            //实验ID
            Set<Long> experimentIds = experimentList.stream().map(KitUsageVo::getExperimentId).collect(Collectors.toSet());
            List<KitTakeGroup> kitTakeGroups = new ArrayList<>();
            experimentIds.forEach(experimentId -> {
                List<KitUsageVo> egroup = experimentList.stream().filter(kitUsageVo -> kitUsageVo.getExperimentId().equals(experimentId)).collect(Collectors.toList());
                //创建时间
                Set<Date> createTimes = egroup.stream().map(KitUsageVo::getCreateTime).collect(Collectors.toSet());
                createTimes.forEach(createTime -> {
                    List<KitUsageVo> last = egroup.stream().filter(kitUsageVo -> kitUsageVo.getCreateTime().equals(createTime)).collect(Collectors.toList());
                    List<KitTakeDeviceList> kitTakeDeviceLists = getKitTakeLists(last, boxPositionData);
                    KitTakeGroup kitTakeGroup = new KitTakeGroup();
                    kitTakeGroup.setDevices(kitTakeDeviceLists);
                    kitTakeGroup.setName(last.get(0).getExperimentName());
                    kitTakeGroups.add(kitTakeGroup);
                });
            });
            resultList.setExperiment(kitTakeGroups);
        }

        //取用历史清单
        List<KitUsageVo> regularList = result.stream().filter(kitUsageVo -> kitUsageVo.getRegularUsageGroupId() != null).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(regularList)) {
            //清单组ID
            Set<Long> regularIds = regularList.stream().map(KitUsageVo::getRegularUsageGroupId).collect(Collectors.toSet());
            List<KitTakeGroup> kitTakeGroups = new ArrayList<>();
            regularIds.forEach(regularId -> {
                List<KitUsageVo> rgroup = regularList.stream().filter(kitUsageVo -> kitUsageVo.getRegularUsageGroupId().equals(regularId)).collect(Collectors.toList());
                //创建时间
                Set<Date> createTimes = rgroup.stream().map(KitUsageVo::getCreateTime).collect(Collectors.toSet());
                createTimes.forEach(createTime -> {
                    List<KitUsageVo> last = rgroup.stream().filter(kitUsageVo -> kitUsageVo.getCreateTime().equals(createTime)).collect(Collectors.toList());
                    List<KitTakeDeviceList> kitTakeDeviceLists = getKitTakeLists(last, boxPositionData);
                    KitTakeGroup kitTakeGroup = new KitTakeGroup();
                    kitTakeGroup.setDevices(kitTakeDeviceLists);
                    Long regularUsageGroupId = last.get(0).getRegularUsageGroupId();
                    KitRegularUsageGroup group = regularUsageGroupService.selectById(regularUsageGroupId);
                    if (group == null) {
                        kitTakeGroup.setName("已删除常用清单" + regularUsageGroupId);
                    } else {
                        kitTakeGroup.setName(group.getName());
                    }
                    kitTakeGroups.add(kitTakeGroup);
                });
            });
            resultList.setRegular(kitTakeGroups);
        }

        return resultList;
    }

    private Map<Long, BoxPositionData> getBoxPositionDataMap(List<KitUsageVo> result) {
        List<Long> kitBoxIdList = result.stream().filter(e -> e.getKitBoxId() != null).map(KitUsageVo::getKitBoxId).distinct().collect(Collectors.toList());
        return panelLogic.getKitBoxPositionData(kitBoxIdList);
    }

    /**
     * 筛选设备分组
     *
     * @param takeList
     * @return
     */
    private List<KitTakeDeviceList> getKitTakeLists(List<KitUsageVo> takeList, Map<Long, BoxPositionData> boxPositionData) {
        List<KitTakeDeviceList> kitTakeDeviceLists = new ArrayList<>();
        Set<Long> rooms = takeList.stream().map(KitUsageVo::getRoomId).collect(Collectors.toSet());
        rooms.forEach(room -> {
            List<KitUsageVo> roomItems = takeList.stream().filter(kitUsageVo -> kitUsageVo.getRoomId().equals(room)).collect(Collectors.toList());
            Set<Long> devices = roomItems.stream().map(KitUsageVo::getDeviceId).collect(Collectors.toSet());
            devices.forEach(device -> {
                KitTakeDeviceList kitTakeDeviceList = new KitTakeDeviceList();
                List<KitUsageVo> deviceItems = takeList.stream().filter(kitUsageVo -> kitUsageVo.getDeviceId().equals(device)).sorted((e1, e2) -> e1.getId() > e2.getId() ? -1 : 1).collect(Collectors.toList());
                deviceItems.forEach(one -> {
                    if (one.getKitBoxId() != null) {
                        BoxPositionData bpd = boxPositionData.get(one.getKitBoxId());
                        one.setPanelColumns(bpd.getColumns());
                        one.setPanelRows(bpd.getRows());
                        one.setGridUsedList(bpd.getPanelGridUsedList());
                    }
                });

                KitUsageVo one = deviceItems.get(0);
                kitTakeDeviceList.setDevice(one.getRoomName() + " -> " + one.getDeviceIndex() + "[" + one.getZone() + "]");
                kitTakeDeviceList.setDeviceId(device);
                kitTakeDeviceList.setRoomName(one.getRoomName());
                kitTakeDeviceList.setDeviceIndex(one.getDeviceIndex());
                kitTakeDeviceList.setZone(one.getZone());
                kitTakeDeviceList.setItems(deviceItems);
                kitTakeDeviceLists.add(kitTakeDeviceList);
            });
        });
        return kitTakeDeviceLists;
    }

    /**
     * 移除清单中的项目
     *
     * @param itemIds
     * @param labId
     * @param labMemberId
     */
    public void removeInventoryFromTakeList(List<Long> itemIds, Long labId, Long labMemberId) {

        Assert.isTrue(!CollectionUtils.isEmpty(itemIds) && labId != null && labMemberId != null, "参数缺失！");

        itemIds.forEach(id -> {
            KitUsage kitUsage = kitUsageService.selectOne(id);
            Assert.notNull(kitUsage, "取用项ID:" + id + "不存在！");
            Assert.isTrue(labId.equals(kitUsage.getLabId()) && labMemberId.equals(kitUsage.getLabMemberId()), "非正常操作！");
        });
        boolean rs = kitUsageService.deleteBatch(itemIds);
        Assert.isTrue(rs, "业务操作失败！");
    }


    /**
     * 取用删除
     *
     * @param usageId
     * @param labId
     * @param labMemberId
     * @return
     */
    public boolean deleteKitUsage(Long usageId, Long labId, Long labMemberId) {

        KitUsage kitUsage = kitUsageService.selectOne(usageId);
        Assert.notNull(kitUsage, "取用项ID:" + usageId + "不存在！");
        Assert.isTrue(labId.equals(kitUsage.getLabId()) && labMemberId.equals(kitUsage.getLabMemberId()), "非正常操作！");

        return kitUsageService.deleteById(usageId);
    }

    /**
     * 登录/未登录扫描待归还列表
     *
     * @param labId
     * @param labMemberId
     * @param usageTime
     * @return
     */
    public List<KitUsageGroup> getUsageList(Long labId, Long labMemberId, Date usageTime) {

        Assert.isTrue(labId != null && labMemberId != null, "参数缺失！");

        List<KitUsageGroup> kitTakeGroups = new ArrayList<>();

        //生成KitUsageVoList
        List<KitUsageVo> result = kitUsageService.getKitUsageVoList(labId, labMemberId, KitUsageEnum.State.NOT_RETURN.getValue());

        //试剂盒位置kitBoxIdList
        Map<Long, BoxPositionData> boxPositionData = getBoxPositionDataMap(result);

        //分出不同的时间戳、设备 下的KitUsageVo
        List<KitUsageVo> usageList = result.stream().filter(kitUsageVo -> kitUsageVo.getUsageTime() != null).collect(Collectors.toList());
        if (usageTime == null) {
            if (!CollectionUtils.isEmpty(usageList)) {
                Set<Date> usageTimes = usageList.stream().map(KitUsageVo::getUsageTime).collect(Collectors.toSet());
                usageTimes.forEach(usageTimeOne -> {
                    KitUsageGroup kitUsageGroup = getKitUsageGroup(usageTimeOne, KitUsageEnum.State.NOT_RETURN.getValue(), usageList, boxPositionData);
                    kitTakeGroups.add(kitUsageGroup);
                });
            }
        } else {
            KitUsageGroup kitUsageGroup = getKitUsageGroup(usageTime, KitUsageEnum.State.NOT_RETURN.getValue(), usageList, boxPositionData);
            kitTakeGroups.add(kitUsageGroup);
        }

        return kitTakeGroups.stream()
                .sorted((v1, v2) -> v1.getUsageTime().getTime() > v2.getUsageTime().getTime() ? -1 : 1)
                .collect(Collectors.toList());
    }

    private KitUsageGroup getKitUsageGroup(Date usageTime, Integer state, List<KitUsageVo> usageList, Map<Long, BoxPositionData> boxPositionData) {
        List<KitUsageVo> last = usageList.stream().filter(kitUsageVo -> kitUsageVo.getUsageTime().equals(usageTime)).collect(Collectors.toList());
        List<KitTakeDeviceList> kitTakeDeviceLists = getKitTakeLists(last, boxPositionData);
        KitUsageGroup kitUsageGroup = new KitUsageGroup();
        if (state.equals(KitUsageEnum.State.RETURNED.getValue())) {
            kitUsageGroup.setItems(last);
        } else {
            kitUsageGroup.setDevices(kitTakeDeviceLists);
        }
        kitUsageGroup.setUsageTime(last.get(0).getUsageTime());
        return kitUsageGroup;
    }

    /**
     * 打印清单列表
     *
     * @param labId
     * @param labMemberId
     * @return
     */
    public PrintPreviewVo getPrintList(Long labId, Long labMemberId, String userName) {

        Assert.isTrue(labId != null && labMemberId != null, "参数缺失！");

        PrintPreviewVo kitUsagePrintVo = null;

        //生成KitUsageVoList
        List<KitUsageVo> result = kitUsageService.getKitUsageVoList(labId, labMemberId, KitUsageEnum.State.TAKE.getValue());

        //分出不同的时间戳、设备 下的KitUsageVo
        List<KitUsageVo> usageList = result.stream().filter(kitUsageVo -> kitUsageVo.getUsageTime() != null).collect(Collectors.toList());

        if (!CollectionUtils.isEmpty(usageList)) {
            kitUsagePrintVo = getKitUsagePrintVo(usageList, userName);

        }

        return kitUsagePrintVo;
    }

    private PrintPreviewVo getKitUsagePrintVo(List<KitUsageVo> usageList, String userName) {
        List<KitUsageDevicePrintVo> KitUsageDevicePrintVoList = getKitUsageDevicePrintVoList(usageList, null);
        PrintPreviewVo kitUsagePrintVo = new PrintPreviewVo();
        kitUsagePrintVo.setItems(KitUsageDevicePrintVoList);
        kitUsagePrintVo.setTakeCount((long) usageList.size());
        kitUsagePrintVo.setUsageTime(new Date());
        kitUsagePrintVo.setUserName(userName);
        return kitUsagePrintVo;
    }

    private List<KitUsageDevicePrintVo> getKitUsageDevicePrintVoList(List<KitUsageVo> last, List<PrintPreviewGet> usages) {
        List<KitUsageDevicePrintVo> KitUsageDevicePrintVoList = new ArrayList<>();
        Set<Long> rooms = last.stream().map(KitUsageVo::getRoomId).collect(Collectors.toSet());
        rooms.forEach(room -> {
            List<KitUsageVo> roomItems = last.stream().filter(kitUsageVo -> kitUsageVo.getRoomId().equals(room)).collect(Collectors.toList());
            Set<Long> devices = roomItems.stream().map(KitUsageVo::getDeviceId).collect(Collectors.toSet());
            devices.forEach(device -> {
                KitUsageDevicePrintVo kitUsageDevicePrintVo = new KitUsageDevicePrintVo();
                List<KitUsageVo> deviceItems = last.stream().filter(kitUsageVo -> kitUsageVo.getDeviceId().equals(device)).sorted((e1, e2) -> {
                    if (e1.getId() != null && e2.getId() != null) {
                        return e1.getId() > e2.getId() ? -1 : 1;
                    } else {
                        return 0;
                    }
                }).collect(Collectors.toList());
                List<KitUsageItemPrintVo> kitUsageItemPrintVoList = deviceItems.stream().map(kitUsageVo -> {
                    KitUsageItemPrintVo kitUsageItemPrintVo = new KitUsageItemPrintVo();
                    kitUsageItemPrintVo.setOperation(UsageOperationEnum.USE.getValue());
                    kitUsageItemPrintVo.setLocation(getLocationStr(kitUsageVo));
                    if (kitUsageVo.getTakeAmount() != null) {
                        kitUsageItemPrintVo.setAmount(kitUsageVo.getTakeAmount());
                    }
                    if (StringUtils.isNotBlank(kitUsageVo.getUnit())) {
                        kitUsageItemPrintVo.setUnit(kitUsageVo.getUnit());
                    }
                    if (kitUsageVo.getId() != null) {
                        kitUsageItemPrintVo.setUsageId(kitUsageVo.getId());
                    }
                    if (StringUtils.isNotBlank(kitUsageVo.getReagentName())) {
                        kitUsageItemPrintVo.setReagentName(kitUsageVo.getReagentName());
                    }
                    if (kitUsageVo.getInventoryId() != null) {
                        kitUsageItemPrintVo.setInventoryId(kitUsageVo.getInventoryId());
                    }
                    if (usages != null && usages.size() > 0) {
                        PrintPreviewGet printPreviewGet = usages.stream().filter(e -> e.getUsageId().equals(kitUsageVo.getId())).findFirst().orElse(null);
                        if (printPreviewGet != null) {
                            kitUsageItemPrintVo.setOperation(printPreviewGet.getOperation());
                        }
                    }
                    return kitUsageItemPrintVo;
                }).collect(Collectors.toList());
                KitUsageVo one = deviceItems.get(0);
                kitUsageDevicePrintVo.setDevice(one.getRoomName() + " -> " + one.getDeviceIndex() + "[" + one.getZone() + "]");
                kitUsageDevicePrintVo.setDeviceId(device);
                kitUsageDevicePrintVo.setItems(kitUsageItemPrintVoList);
                KitUsageDevicePrintVoList.add(kitUsageDevicePrintVo);
            });
        });
        return KitUsageDevicePrintVoList;
    }

    /**
     * 获取物料未归还的分页列表
     *
     * @param labMemberId
     * @param pageNum
     * @param pageSize
     * @return
     */
    public PageVo<KitUsageVo> getNotRetureUsageList(Long labMemberId, Integer state, Integer pageNum, Integer pageSize) {
        Assert.isTrue(labMemberId != null && pageNum != null && pageSize != null, "参数缺失！");
        Assert.isTrue(state.equals(KitUsageEnum.State.NOT_RETURN.getValue()), "state value not correct");
        return kitUsageService.getNotRetureUsageList(labMemberId, state, pageNum, pageSize);
    }


    /**
     * 取用历史列表
     *
     * @param labId
     * @param labMemberId
     * @return
     */
    public PageVo<KitUsageGroup> getUsageHistoryList(Long labId, Long labMemberId, Integer pageNum, Integer pageSize) {

        Assert.isTrue(labId != null && labMemberId != null && pageNum != null && pageSize != null, "参数缺失！");

        List<KitUsageGroup> kitTakeGroups = new ArrayList<>();

        PageVo<KitUsageVo> kitUsagePage = kitUsageService.getKitUsageVoPage(labId, labMemberId, pageNum, pageSize, KitUsageEnum.State.RETURNED.getValue(), KitUsageEnum.State.NOT_RETURN.getValue());

        //生成KitUsageVoList
        List<KitUsageVo> result = kitUsagePage.getContent();


        //分出不同的时间戳、设备 下的KitUsageVo
        List<KitUsageVo> usageList = result.stream().filter(kitUsageVo -> kitUsageVo.getUsageTime() != null).collect(Collectors.toList());

        if (!CollectionUtils.isEmpty(usageList)) {
            Set<Date> usageTimes = usageList.stream().map(KitUsageVo::getUsageTime).collect(Collectors.toSet());
            usageTimes.forEach(usageTimeOne -> {
                List<KitUsageVo> last = usageList.stream().filter(kitUsageVo -> kitUsageVo.getUsageTime().equals(usageTimeOne)).collect(Collectors.toList());
                KitUsageGroup kitUsageGroup = new KitUsageGroup();
                kitUsageGroup.setItems(last);
                kitUsageGroup.setUsageTime(last.get(0).getUsageTime());
                kitTakeGroups.add(kitUsageGroup);
            });
        }

        //排序
        List<KitUsageGroup> last = kitTakeGroups.stream().sorted((e1, e2) -> {
            return e1.getUsageTime().getTime() > e2.getUsageTime().getTime() ? -1 : 1;
        }).collect(Collectors.toList());

        PageVo<KitUsageGroup> rs = new PageVo<>();
        rs.setStartRow(kitUsagePage.getStartRow());
        rs.setTotalRow(kitUsagePage.getTotalRow());
        rs.setTotalPage(kitUsagePage.getTotalPage());
        rs.setPageSize(kitUsagePage.getPageSize());
        rs.setPageNum(kitUsagePage.getPageNum());
        rs.setHasNext(kitUsagePage.isHasNext());
        rs.setHasPrevious(kitUsagePage.isHasPrevious());
        rs.setContent(last);

        return rs;
    }

    /**
     * 登录取用归还/清空(废除)
     *
     * @param userInfo
     * @param items
     */
    @Deprecated
    public void returnInventory(UserInfoVo userInfo, List<KitUsageReturn> items, String endPoint) {

        Assert.isTrue(userInfo != null && !CollectionUtils.isEmpty(items), "参数缺失！");

        List<LabMemberPower> labMemberPowers = labMemberPowerService.selectList(userInfo.getLabId(), userInfo.getLabMemberId());
        Lab lab = labService.selectById(userInfo.getLabId());

        List<Long> usageIds = items.stream().map(KitUsageReturn::getUsageId).distinct().collect(Collectors.toList());
        List<KitUsage> exits = kitUsageService.selectList(usageIds);
        List<KitUsage> kitUsageUpdateList = new ArrayList<>();
        List<ReagentInventory> inventoryUpdateList = new ArrayList<>();
        List<Long> deleteIds = new ArrayList<>();
        List<Long> deleteSampleIds = new ArrayList<>();
        Set<Long> returnKitIds = new HashSet<>();
        Set<Long> clearKitIds = new HashSet<>();

        //对应的取用信息归还（量大于可用量扣完为止） / 清空
        items.forEach(kitUsageReturn -> {
            Assert.isTrue(kitUsageReturn.getType() != null && kitUsageReturn.getUsageId() != null && kitUsageReturn.getUseAmount() != null, "请求参数缺失！");
            KitUsage kitUsageEx = exits.stream().filter(e -> e.getId().equals(kitUsageReturn.getUsageId())).findFirst().orElse(null);
            Assert.isTrue(kitUsageEx != null && kitUsageEx.getState().equals(KitUsageEnum.State.NOT_RETURN.getValue()), "试剂使用条目ID:" + kitUsageReturn.getUsageId() + ",并未被取用！");
            KitUsage kitUsage = MyBeanUtils.copyBean(kitUsageEx, KitUsage.class);
            if (endPoint.equals(ClientTypeEnum.WEB.getValue()) || endPoint.equals(ClientTypeEnum.AIO.getValue()) 
            		|| endPoint.equals(ClientTypeEnum.PC.getValue())) {
                kitUsage.setReturnSuccess(BoolEnum.TRUE.getValue());
            }
            ReagentInventory reagentInventory = reagentInventoryService.selectById(kitUsage.getInventoryId());
            assertInventoryBelongToLabAndLabMember(userInfo, reagentInventory, labMemberPowers, lab);
            if (kitUsageReturn.getType().equals(UsageOperationEnum.RETURN.getValue())) {
                //归还
                BigDecimal amount = reagentInventory.getAmount();
                BigDecimal takeAmount = kitUsage.getTakeAmount();
                BigDecimal useAmount = kitUsageReturn.getUseAmount();
                BigDecimal more = takeAmount.subtract(useAmount);

                Assert.isTrue(takeAmount.compareTo(BigDecimal.valueOf(0)) >= 0, "取用量不能为负值！");
                Assert.isTrue(useAmount.compareTo(BigDecimal.valueOf(0)) >= 0, "使用量不能为负值！");

                BigDecimal last = amount.add(more);
                BigDecimal zero = new BigDecimal(0);

                //设置状态已归还
                kitUsage.setState(KitUsageEnum.State.RETURNED.getValue());
                kitUsage.setUseAmount(last.compareTo(zero) < 0 ? amount : useAmount);
                kitUsage.setTakeAmount(useAmount);
                kitUsageUpdateList.add(kitUsage);
                //扣去用量设置余量
                reagentInventory.setAmount(last.compareTo(zero) < 0 ? zero : last);
                reagentInventory.setInUse(0);
                inventoryUpdateList.add(reagentInventory);
                returnKitIds.add(reagentInventory.getKitId());
            } else if (kitUsageReturn.getType().equals(UsageOperationEnum.EMPTY.getValue())) {
                //设置状态已归还
                kitUsage.setState(KitUsageEnum.State.RETURNED.getValue());
                kitUsage.setUseAmount(reagentInventory.getAmount());
                kitUsageUpdateList.add(kitUsage);
                //清空库存
                deleteIds.add(reagentInventory.getId());
                clearKitIds.add(reagentInventory.getKitId());
                //如果是样品，同类库存都没有后删除样品
                List<ReagentInventory> inventoryList = reagentInventoryService.selectListByKitId(reagentInventory.getKitId());
                if (inventoryList != null && inventoryList.size() == 1 && inventoryList.get(0).getId().equals(kitUsage.getInventoryId())
                        && KitEnum.Classify.SAMPLE.getValue().equals(inventoryList.get(0).getClassify())) {
                    deleteSampleIds.add(reagentInventory.getKitId());
                }
            }
        });

        if (!CollectionUtils.isEmpty(kitUsageUpdateList)) {
            kitUsageService.updateBatch(kitUsageUpdateList);
        }
        if (!CollectionUtils.isEmpty(inventoryUpdateList)) {
            reagentInventoryService.updateInventoryListAmount(inventoryUpdateList);
        }
        if (!CollectionUtils.isEmpty(deleteIds)) {
            reagentInventoryLogic.deleteInventoryByIdList(deleteIds);
        }
        if (!CollectionUtils.isEmpty(deleteSampleIds)) {
            // 删除样品
            deleteSampleIds.forEach(sampleId -> {
                reagentLogic.delete(sampleId, userInfo.getLabMemberId());
            });
        }
        //归还记录
        if (!CollectionUtils.isEmpty(returnKitIds)) {
            inventoryRecordService.add(userInfo, new ArrayList<>(returnKitIds), InventoryRecordEnum.RETURN);
        }
        //清空记录
        if (!CollectionUtils.isEmpty(clearKitIds)) {
            inventoryRecordService.add(userInfo, new ArrayList<>(clearKitIds), InventoryRecordEnum.EMPTY);
        }
    }

    /**
     * kit加入取用清单/待取用
     *
     * @param kitId
     * @param groupId
     * @param amount
     * @param user
     * @param takeType
     * @return
     */
    public List<KitUsage> addKitGroupInventoryToTakeOrTaking(Long kitId, Long groupId, BigDecimal amount, UserInfoVo user, KitTakeType takeType, String endPoint) {

        //获取库存
        Date updateTime = new Date();
        List<ReagentInventory> invList = reagentInventoryService.getInventoryList(kitId, null, groupId);
        Assert.isTrue(invList != null && invList.size() > 0, "库存不存在");
        List<KitSpec> specList = kitSpecService.getKitSpecListBySpecId(invList.get(0).getKitSpecId());

        List<Long> reagentTypes = invList.stream().map(ReagentInventory::getReagentTypeId).distinct().collect(Collectors.toList());
        Map<Long, Long> firstReagentTypeMap = reagentTypeService.selectFirstReagentTypeMap(reagentTypes);

        BigDecimal kitAmount = reagentInventoryLogic.getOneGroupKitAmount(kitId, groupId, null, specList);
        Assert.isTrue(kitAmount.compareTo(BigDecimal.valueOf(0)) >= 0, "Kit 可用量为0，无法取用！");

        List<KitUsage> takeList = new ArrayList<>();
        List<KitUsage> usageList = new ArrayList<>();
        List<KitUsage> useAndHasLock = new ArrayList<>();
        List<ReagentInventory> leftList = new ArrayList<>();
        List<KitUsage> exists = kitUsageService.selectList(user.getLabId(), user.getLabMemberId(), KitUsageEnum.State.TAKE.getValue());
        List<KitUsage> exists1 = kitUsageService.selectList(user.getLabId(), user.getLabMemberId(), KitUsageEnum.State.TAKING.getValue());
        exists.addAll(exists1);
        //根据规格循环
        specList.forEach(s -> {
            //需求变更，kitGroup中所有Inventory按比例取 size*(amount/kitSize) ?
            //s.getReagentId() 对应试剂需要取用的量
//            BigDecimal thisSize=amount.multiply(BigDecimal.valueOf(s.getMultiple()).multiply(s.getSize())).divide(s.getKitSize(),3,RoundingMode.HALF_UP);
            BigDecimal thisSize = amount.multiply(s.getSize().divide(s.getKitSize(), 3, RoundingMode.HALF_UP));
            //s.getReagentId() 对应试剂 该次所有库存
            List<ReagentInventory> thisInvList = invList.stream().filter(i -> i.getReagentId().equals(s.getReagentId())).collect(Collectors.toList());

            //成分未入库,无法取用
            Assert.isTrue(thisInvList.size() > 0, "试剂存在成分未入库，无法取用！");

            //分有锁无锁
            List<ReagentInventory> hasLocks = new ArrayList<>();
            List<ReagentInventory> noLocks = new ArrayList<>();
            divideIntoHasLockAndNoLock(thisInvList, hasLocks, noLocks);

            //循环取量
            divideIntoTakeListAndUsageList(user, takeType, updateTime, takeList, usageList,
                    useAndHasLock, exists, s, thisSize, hasLocks, leftList, true, endPoint, firstReagentTypeMap);
            divideIntoTakeListAndUsageList(user, takeType, updateTime, takeList, usageList,
                    useAndHasLock, exists, s, thisSize, noLocks, leftList, false, endPoint, firstReagentTypeMap);

        });
        if (takeList.size() > 0) {
            Integer integer = kitUsageService.saveTakeList(takeList);
            Assert.isTrue(integer == takeList.size(), "操作失败！");
        }

        if (usageList.size() > 0) {
            Integer rs = kitUsageService.updateBatch(usageList);
            Assert.isTrue(rs == usageList.size(), "操作失败！");
        }

        if (leftList.size() > 0) {
            reagentInventoryService.updateInventoryListAmount(leftList);
            //取用记录
            inventoryRecordService.add(user, kitId, InventoryRecordEnum.TAKE);
        }

        List<Long> kitUsageIds = useAndHasLock.stream().map(KitUsage::getId).distinct().collect(Collectors.toList());
        if (useAndHasLock.size() > 0) {
            //发送开锁权限
            sendUnlockPowerListToAio(user, useAndHasLock);
            //定时任务 24小时未开锁取用
            createTakingReturningJob(kitUsageIds, KitUsageEnum.State.TAKING.getValue(), 24 * 60 * 60 * 1000L);
        }
        return takeList;
    }

    private void divideIntoHasLockAndNoLock(List<ReagentInventory> thisInvList, List<ReagentInventory> hasLocks,
                                            List<ReagentInventory> noLocks) {
        List<Long> invIds = thisInvList.stream().map(ReagentInventory::getId).collect(Collectors.toList());
        List<ItemLock> itemLocks = deviceService.selectDeviceLockMapByInvId(invIds);
        thisInvList.forEach(inventory -> {
            Assert.isTrue(inventory.getId() != null, "请求参数缺失！");
            ItemLock itemLock = itemLocks.stream().filter(e -> e.getId().equals(inventory.getId())).findFirst().orElse(null);
            if (itemLock != null && itemLock.getHasLock().equals(1)) {
                hasLocks.add(inventory);
            } else {
                noLocks.add(inventory);
            }
        });
    }

    private void divideIntoTakeListAndUsageList(UserInfoVo user, KitTakeType takeType, Date updateTime,
                                                List<KitUsage> takeList, List<KitUsage> usageList, List<KitUsage> useAndHasLock,
                                                List<KitUsage> exists, KitSpec s, BigDecimal thisSize,
                                                List<ReagentInventory> thisInvList, List<ReagentInventory> leftList, boolean hasLock, String endPoint,
                                                Map<Long, Long> firstReagentTypeMap) {
        for (ReagentInventory inv : thisInvList) {
            KitUsage usage = new KitUsage();
            usage.setInventoryId(inv.getId());
            usage.setKitId(inv.getKitId());
            usage.setLabId(inv.getLabId());
            usage.setLabMemberId(user.getLabMemberId());
            usage.setLabMemberName(user.getName());
            usage.setReagentId(s.getReagentId());
            usage.setReagentName(inv.getReagentName());
            usage.setClassify(inv.getClassify());
            usage.setFirstReagentTypeId(firstReagentTypeMap.get(inv.getReagentTypeId()));

            //可用量小于0跳过
            if (inv.getAmount().compareTo(BigDecimal.valueOf(0)) == 0) {
                continue;
            }

            //设置取用量，合并已存在取用清单项
            if (takeType.equals(KitTakeType.TAKE_TO_LIST)) {
                //加入取用清单
                Optional<KitUsage> first = exists.stream().filter(e -> e.getInventoryId().equals(inv.getId()) && e.getState().equals(KitUsageEnum.State.TAKE.getValue())).findFirst();
                if (!first.isPresent()) {
                    usage.setState(KitUsageEnum.State.TAKE.getValue());
                    setUseAmount(thisSize, inv, usage);
                    takeList.add(usage);
                } else {
                    usage = first.get();
                    if (inv.getAmount().compareTo(thisSize) > 0) {
                        usage.setTakeAmount(usage.getTakeAmount().add(thisSize));
                    } else {
                        usage.setTakeAmount(usage.getTakeAmount().add(inv.getAmount()));
                    }
                    usage.setUpdateTime(updateTime);
                    usageList.add(usage);
                }
            } else {

                //加入待取用清单
                if (hasLock) {
                    Optional<KitUsage> first = exists.stream().filter(e -> e.getInventoryId().equals(inv.getId()) && e.getState().equals(KitUsageEnum.State.TAKING.getValue())).findFirst();
                    usage.setState(KitUsageEnum.State.TAKING.getValue());
                    if (!first.isPresent()) {
                        //开锁权限
                        setUseAmount(thisSize, inv, usage);
                        usage.setUsageTime(updateTime);
                        takeList.add(usage);
                    } else {
                        usage = first.get();
                        if (inv.getAmount().compareTo(thisSize.add(usage.getTakeAmount())) > 0) {
                            usage.setTakeAmount(thisSize.add(usage.getTakeAmount()));
                        } else {
                            usage.setTakeAmount(inv.getAmount());
                        }
                        usageList.add(usage);
                    }
                    useAndHasLock.add(usage);

                } else {
                    if (endPoint.equals(ClientTypeEnum.WEB.getValue()) || endPoint.equals(ClientTypeEnum.AIO.getValue())
                    		|| endPoint.equals(ClientTypeEnum.PC.getValue())) {
                        usage.setTakeSuccess(BoolEnum.TRUE.getValue());
                    }
                    usage.setState(KitUsageEnum.State.NOT_RETURN.getValue());
                    usage.setUsageTime(updateTime);
                    setUseAmount(thisSize, inv, usage);
                    takeList.add(usage);
                    //扣量
                    ReagentInventory leftInv = new ReagentInventory();
                    leftInv.setId(inv.getId());
                    leftInv.setAmount(inv.getAmount().compareTo(thisSize) > 0 ? inv.getAmount().subtract(thisSize) : BigDecimal.valueOf(0));
                    leftInv.setInUse(inv.getInUse());
                    leftList.add(leftInv);
                }

            }

        }
    }

    private void setUseAmount(BigDecimal thisSize, ReagentInventory inv, KitUsage usage) {
        if (inv.getAmount().compareTo(thisSize) >= 0) {
            usage.setTakeAmount(thisSize);
        } else {
            usage.setTakeAmount(inv.getAmount());
        }
    }

    /**
     * 未登录扫码查询（扫描试剂条形码）
     *
     * @param inventoryId
     * @return
     */
    public KitUsageWithKitInfo getKitUsageResp(Long inventoryId) {

        Assert.notNull(inventoryId, "参数缺失！");

        Map<Integer, String> unitMap = dictService.getUnitMap();
        Map<Integer, String> zoneMap = dictService.getZoneMap();

        ReagentInventory reagentInventory = reagentInventoryService.selectById(inventoryId);
        Assert.notNull(reagentInventory, "试剂库存ID:" + inventoryId + "不存在");

        Reagent reagent = reagentService.selectById(reagentInventory.getReagentId());
        Assert.notNull(reagent, "Reagent不存在！");

        Kit kit = kitService.selectById(reagentInventory.getKitId());
        Assert.notNull(kit, "Kit不存在！");

        KitSpec kitSpec = kitSpecService.selectById(reagentInventory.getKitSpecId());
        Assert.notNull(kitSpec, "Kit规格不存在！");

        ReagentType reagentType = reagentTypeService.selectById(reagentInventory.getReagentTypeId());

        String kitUnit = unitMap.get(kit.getUnit());
        String kitZone = zoneMap.get(kit.getZone());

        String regeantUnit = unitMap.get(reagentInventory.getUnit());
        String regeantZone = zoneMap.get(reagentInventory.getZone());

        KitUsageWithKitInfo kitUsageWithKitInfo = new KitUsageWithKitInfo();
        kitUsageWithKitInfo.setKitRemark(kit.getRemark());
        kitUsageWithKitInfo.setKitName(kit.getName());
        kitUsageWithKitInfo.setKitItemNo(kit.getItemNo());
        kitUsageWithKitInfo.setQualityDay(kit.getQualityDay());
        kitUsageWithKitInfo.setWarnAmount(kit.getWarnamount());
        kitUsageWithKitInfo.setKitUnit(kitUnit);
        kitUsageWithKitInfo.setCompany(kit.getCompany());
        kitUsageWithKitInfo.setWebsite(kit.getWebsite());
        kitUsageWithKitInfo.setKitAlias(kit.getAlias());
        kitUsageWithKitInfo.setKitZone(kitZone);
        kitUsageWithKitInfo.setKitSize(kitSpec.getKitSize());
        kitUsageWithKitInfo.setReagentSize(kitSpec.getSize());
        kitUsageWithKitInfo.setReagentName(reagentInventory.getReagentName());
        kitUsageWithKitInfo.setReagentType(reagentType != null ? reagentType.getName() : null);
        kitUsageWithKitInfo.setReagentZone(regeantZone);
        kitUsageWithKitInfo.setReagentUnit(regeantUnit);
        kitUsageWithKitInfo.setReagentItemNo(reagent.getItemNo());
        kitUsageWithKitInfo.setReagentAlias(reagent.getAlias());
        kitUsageWithKitInfo.setReagentRemark(reagent.getRemark());
        kitUsageWithKitInfo.setKitId(reagentInventory.getKitId());
        kitUsageWithKitInfo.setReagentId(reagentInventory.getReagentId());
        kitUsageWithKitInfo.setInventoryId(reagentInventory.getId());
        kitUsageWithKitInfo.setUserName(getUserName(inventoryId));

        return kitUsageWithKitInfo;
    }

    /**
     * 获取取用人姓名，使用最后一位去用人
     *
     * @param inventoryId
     * @return
     */
    private String getUserName(Long inventoryId) {
        Assert.notNull(inventoryId, "参数缺失！");
        List<KitUsage> kitUsages = kitUsageService.selectList(inventoryId, KitUsageEnum.State.TAKING.getValue());
        if (!CollectionUtils.isEmpty(kitUsages)) {
            KitUsage kitUsage = kitUsages.get(0);
            return kitUsage.getLabMemberName();
        }
        return null;
    }

    /**
     * 获取试剂首页历史、取用、清单统计数据
     *
     * @return
     */
    public KitUsageCountVo getKitUsageCountVo(Long labId, Long labMemberId) {

        Assert.isTrue(labId != null && labMemberId != null, "没有关联的实验室！");

        Integer list = kitUsageService.selectCount(labId, labMemberId, KitUsageEnum.State.TAKE.getValue());
        Integer usage = kitUsageService.selectCount(labId, labMemberId, KitUsageEnum.State.NOT_RETURN.getValue());
        Integer history = kitUsageService.selectCount(labId, labMemberId, KitUsageEnum.State.NOT_RETURN.getValue(), KitUsageEnum.State.RETURNED.getValue());

        return new KitUsageCountVo(history, list, usage);
    }

    /**
     * 获取试剂使用状态与使用人
     *
     * @param kitId
     * @param inventoryId
     * @return
     */
    public KitUsageState getKitUsageState(Long kitId, Long groupId, Long inventoryId) {
        List<KitUsage> kitUsages = null;
        if (kitId != null && groupId == null) {
            //kit
            kitUsages = kitUsageService.selectByKitId(kitId, KitUsageEnum.State.NOT_RETURN.getValue());
        } else if (kitId != null && groupId != null) {
            List<ReagentInventory> inventoryList = reagentInventoryService.getInventoryList(kitId, null, groupId);
            Assert.isTrue(!CollectionUtils.isEmpty(inventoryList), "试剂组合不存在！");
            List<Long> inventoryIds = inventoryList.stream().map(ReagentInventory::getId).distinct().collect(Collectors.toList());
            kitUsages = kitUsageService.selectListInInventoryIds(inventoryIds, KitUsageEnum.State.NOT_RETURN.getValue());
        } else if (inventoryId != null) {
            //inventory
            kitUsages = kitUsageService.selectList(inventoryId, KitUsageEnum.State.NOT_RETURN.getValue());
        }

        KitUsageState state = new KitUsageState();

        //设置使用信息
        if (CollectionUtils.isEmpty(kitUsages)) {
            state.setInUse(false);
            state.setUserName(null);
        } else {
            KitUsage kitUsage = kitUsages.get(0);
            state.setInUse(kitUsage.getLabMemberId() != null);
            state.setUserName(kitUsage.getLabMemberName());
        }

        return state;
    }

    /**
     * 批量获取试剂使用状态与使用人
     *
     * @param usageIds
     * @return
     */
    public List<KitUsageState> getKitUsageStateList(List<Long> usageIds) {

        if (usageIds != null && usageIds.size() > 0) {
            //KitUsageVo
            List<KitUsage> usages = kitUsageService.selectList(usageIds)
                    .stream().filter(e -> e.getState().equals(KitUsageEnum.State.TAKE.getValue())).collect(Collectors.toList());

            //inventoryIds
            List<Long> inventoryIds = usages.stream().map(KitUsage::getInventoryId).distinct().collect(Collectors.toList());

            if (inventoryIds != null && inventoryIds.size() > 0) {
                //inUse
                List<KitUsage> inUse = kitUsageService.selectListInInventoryIds(inventoryIds, KitUsageEnum.State.NOT_RETURN.getValue(), KitUsageEnum.State.RETURNING.getValue());

                List<ReagentInventory> inventories = reagentInventoryService.selectList(inventoryIds, BoolEnum.FALSE.getValue());

                //封装使用信息
                List<KitUsageState> states = inventoryIds.stream().map(inventoryId -> {

                    List<KitUsage> invUsages = inUse.stream().filter(e -> e.getInventoryId().equals(inventoryId) && e.getState().equals(KitUsageEnum.State.NOT_RETURN.getValue())).collect(Collectors.toList());

                    ReagentInventory inventory = inventories.stream().filter(e -> e.getId().equals(inventoryId)).findFirst().orElse(null);

                    if (inventory != null) {

                        KitUsageState state = new KitUsageState();
                        //设置使用信息
                        if (CollectionUtils.isEmpty(invUsages)) {
                            return null;
                        } else {
                            KitUsage kitUsage = invUsages.get(0);
                            state.setInUse(kitUsage.getLabMemberId() != null);
                            state.setUserName(kitUsage.getLabMemberName());
                            state.setReagentName(inventory.getReagentName());
                            state.setKitType(inventory.getKitType());
                        }
                        return state;
                    }
                    return null;
                }).filter(Objects::nonNull).collect(Collectors.toList());

                return states;
            }
        }
        return new ArrayList<>(0);
    }

    /**
     * 修改余量
     *
     * @param usageId
     * @param amount
     * @param userInfo
     * @return
     */
    public boolean modifyInventoryAmount(Long usageId, BigDecimal amount, UserInfoVo userInfo) {

        Assert.isTrue(usageId != null && amount != null && userInfo != null, "参数缺失！");
        Assert.isTrue(amount.compareTo(BigDecimal.valueOf(0)) >= 0, "余量不能小于0！");

        List<LabMemberPower> labMemberPowers = labMemberPowerService.selectList(userInfo.getLabId(), userInfo.getLabMemberId());
        Lab lab = labService.selectById(userInfo.getLabId());

        KitUsage kitUsage = kitUsageService.selectOne(usageId, userInfo.getLabId(), userInfo.getLabMemberId(), KitUsageEnum.State.NOT_RETURN.getValue());
        Assert.notNull(kitUsage, "取用项不存在！");

        ReagentInventory reagentInventory = reagentInventoryService.selectById(kitUsage.getInventoryId());
        Assert.notNull(reagentInventory, "试剂成分库存不存在！");

        assertInventoryBelongToLabAndLabMember(userInfo, reagentInventory, labMemberPowers, lab);

        reagentInventory.setAmount(amount);

        return reagentInventoryService.updateById(reagentInventory);
    }

    private void assertInventoryBelongToLabAndLabMember(UserInfoVo userInfo, ReagentInventory reagentInventory, List<LabMemberPower> powers, Lab lab) {
        Assert.isTrue(reagentInventory.getIsDelete().equals(0), "试剂库存已被删除！");
        Assert.isTrue(reagentInventory.getLabId().equals(userInfo.getLabId()), "试剂库存不属于该实验室！");
        //owner
        if (lab.getOwnerId().equals(userInfo.getId())) {
            return;
        }
        //reagent power
        for (LabMemberPower labMemberPower : powers) {
            if (labMemberPower.getPower().equals(LabMemberPowerEnum.reagent)) {
                return;
            }
        }
        //self
        if (reagentInventory.getLabMemberId() != null) {
            Assert.isTrue(reagentInventory.getLabMemberId().equals(userInfo.getLabMemberId()), "试剂库存不属于该实验室成员！");
        }
    }

    private ReagentInventory getReagentInventoryFromMap(Map<Long, ReagentInventory> inventoryMap, Long inventoryId) {
        ReagentInventory reagentInventory = inventoryMap.get(inventoryId);
        if (reagentInventory == null && !inventoryMap.containsKey(inventoryId)) {
            reagentInventory = reagentInventoryService.selectById(inventoryId);
            inventoryMap.put(inventoryId, reagentInventory);
        }
        return reagentInventory;
    }

    private Kit getKitFromMap(Map<Long, Kit> kitMap, Long kitId) {
        Kit kit = kitMap.get(kitId);
        if (kit == null && !kitMap.containsKey(kitId)) {
            kit = kitService.selectById(kitId);
            kitMap.put(kitId, kit);
        }
        return kit;
    }


    /**
     * 取用中列表
     *
     * @param labId
     * @param labMemberId
     * @return
     * @time 2019-02-15
     */
    public List<KitTakeDeviceList> getTakingList(Long labId, Long labMemberId) {

        Assert.isTrue(labId != null && labMemberId != null, "参数缺失！");

        //生成KitUsageVoList
        List<KitUsageVo> result = kitUsageService.getKitUsageVoList(labId, labMemberId, KitUsageEnum.State.TAKING.getValue());

        //试剂盒位置kitBoxIdList
        Map<Long, BoxPositionData> boxPositionData = getBoxPositionDataMap(result);

        return this.getKitTakeLists(result, boxPositionData);
    }


    /**
     * 从清单中取用到取用中
     */
    public void kitTakeToTaking(List<KitUsageAdd> kitUsageAdds, UserInfoVo userInfo) {

        Assert.isTrue(!CollectionUtils.isEmpty(kitUsageAdds) && userInfo != null, "参数缺失！");

        List<LabMemberPower> labMemberPowers = labMemberPowerService.selectList(userInfo.getLabId(), userInfo.getLabMemberId());
        Lab lab = labService.selectById(userInfo.getLabId());

        List<Long> usageIds = kitUsageAdds.stream().map(KitUsageAdd::getUsageId).distinct().collect(Collectors.toList());
        List<KitUsage> exits = kitUsageService.selectList(usageIds);
        List<KitUsage> updateList = new ArrayList<>();

        Map<Long, ReagentInventory> inventoryMap = new HashMap<>();
        Map<Long, Kit> kitMap = new HashMap<>();

        Date updateTime = new Date();
        kitUsageAdds.forEach(kitUsageAdd -> {
            Assert.isTrue(kitUsageAdd.getUsageId() != null && kitUsageAdd.getAmount() != null, "请求参数异常！");

            KitUsage kitUsageEx = exits.stream().filter(e -> e.getId().equals(kitUsageAdd.getUsageId())).findFirst().orElse(null);
            Assert.isTrue(kitUsageEx != null && kitUsageEx.getState().equals(KitUsageEnum.State.TAKE.getValue()), "试剂取用条目ID:" + kitUsageAdd.getUsageId() + ",并未被取用！");
            KitUsage kitUsage = MyBeanUtils.copyBean(kitUsageEx, KitUsage.class);
            Assert.notNull(kitUsage, "取用项不存在！");

            Kit kit = getKitFromMap(kitMap, kitUsage.getKitId());
            Assert.notNull(kit, "试剂不存在！");

            ReagentInventory reagentInventory = getReagentInventoryFromMap(inventoryMap, kitUsage.getInventoryId());
            Assert.notNull(reagentInventory, "取用项试剂库存不存在！");

            assertInventoryBelongToLabAndLabMember(userInfo, reagentInventory, labMemberPowers, lab);

            BigDecimal takeAmount = kitUsageAdd.getAmount();
            BigDecimal amount = reagentInventory.getAmount();
            BigDecimal last = amount.subtract(takeAmount);
            BigDecimal zero = new BigDecimal(0);

            Assert.isTrue(takeAmount.compareTo(BigDecimal.valueOf(0)) >= 0, "取用量不能为负值！");

            //更新取用信息
            kitUsage.setTakeAmount(last.compareTo(zero) < 0 ? amount : takeAmount);
            kitUsage.setState(KitUsageEnum.State.TAKING.getValue());
            kitUsage.setUpdateTime(updateTime);
            kitUsage.setUsageTime(updateTime);
            updateList.add(kitUsage);
        });

        List<Long> kitUsageIds = updateList.stream().map(KitUsage::getId).distinct().collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(updateList)) {
            kitUsageService.updateBatch(updateList);
            //推送开锁权限
            sendUnlockPowerListToAio(userInfo, updateList);
            //定时任务 24小时未开锁取用
            createTakingReturningJob(kitUsageIds, KitUsageEnum.State.TAKING.getValue(), 24 * 60 * 60 * 1000L);
        }

    }

    /**
     * 从清单中取用（优化）
     */
    public void kitTakeToKitNotReturn(List<KitUsageAdd> kitUsageAdds, UserInfoVo userInfo, String endPoint) {

        Assert.isTrue(!CollectionUtils.isEmpty(kitUsageAdds) && userInfo != null, "参数缺失！");

        List<LabMemberPower> labMemberPowers = labMemberPowerService.selectList(userInfo.getLabId(), userInfo.getLabMemberId());
        Lab lab = labService.selectById(userInfo.getLabId());

        Date usageTime = new Date();
        List<Long> usageIds = kitUsageAdds.stream().map(KitUsageAdd::getUsageId).distinct().collect(Collectors.toList());
        List<KitUsage> exits = kitUsageService.selectList(usageIds);
        List<KitUsage> updateList = new ArrayList<>();
        List<ReagentInventory> updateIvnList = new ArrayList<>();

        Map<Long, ReagentInventory> inventoryMap = new HashMap<>();
        Map<Long, Kit> kitMap = new HashMap<>();

        kitUsageAdds.forEach(kitUsageAdd -> {
            Assert.isTrue(kitUsageAdd.getUsageId() != null && kitUsageAdd.getAmount() != null, "请求参数异常！");

            KitUsage kitUsageEx = exits.stream().filter(e -> e.getId().equals(kitUsageAdd.getUsageId())).findFirst().orElse(null);
            Assert.isTrue(kitUsageEx != null && kitUsageEx.getState().equals(KitUsageEnum.State.TAKE.getValue()), "试剂取用条目ID:" + kitUsageAdd.getUsageId() + ",并未被取用！");
            KitUsage kitUsage = MyBeanUtils.copyBean(kitUsageEx, KitUsage.class);

            Kit kit = getKitFromMap(kitMap, kitUsage.getKitId());
            Assert.notNull(kit, "试剂不存在！");

            ReagentInventory reagentInventory = getReagentInventoryFromMap(inventoryMap, kitUsage.getInventoryId());
            Assert.notNull(reagentInventory, "取用项试剂库存不存在！");

            assertInventoryBelongToLabAndLabMember(userInfo, reagentInventory, labMemberPowers, lab);

            BigDecimal takeAmount = kitUsageAdd.getAmount();
            BigDecimal amount = reagentInventory.getAmount();
            BigDecimal last = amount.subtract(takeAmount);
            BigDecimal zero = new BigDecimal(0);

            Assert.isTrue(takeAmount.compareTo(BigDecimal.valueOf(0)) >= 0, "取用量不能为负值！");

            //更新取用信息
            kitUsage.setTakeAmount(last.compareTo(zero) < 0 ? amount : takeAmount);
            kitUsage.setUsageTime(usageTime);
            kitUsage.setState(KitUsageEnum.State.NOT_RETURN.getValue());
            if (endPoint.equals(ClientTypeEnum.WEB.getValue()) || endPoint.equals(ClientTypeEnum.AIO.getValue())
            		|| endPoint.equals(ClientTypeEnum.PC.getValue())) {
                kitUsage.setTakeSuccess(BoolEnum.TRUE.getValue());
            }
            updateList.add(kitUsage);
            //更新试剂信息
            reagentInventory.setAmount(last.compareTo(zero) < 0 ? zero : last);
            reagentInventory.setInUse(1);
            updateIvnList.add(reagentInventory);
        });

        if (!CollectionUtils.isEmpty(updateList) && !CollectionUtils.isEmpty(updateIvnList)) {
            Set<Long> kitIds = updateList.stream().map(KitUsage::getKitId).collect(Collectors.toSet());
            kitUsageService.updateBatch(updateList);
            reagentInventoryService.updateInventoryListAmount(updateIvnList);
            //取用记录
            inventoryRecordService.add(userInfo, new ArrayList<>(kitIds), InventoryRecordEnum.TAKE);
        }
    }

    /**
     * 归还中清单
     */
    public List<KitTakeDeviceList> getReturningList(Long labId, Long labMemberId) {

        Assert.isTrue(labId != null && labMemberId != null, "参数缺失！");

        //生成KitUsageVoList
        List<KitUsageVo> result = kitUsageService.getKitUsageVoList(labId, labMemberId, KitUsageEnum.State.RETURNING.getValue());

        //试剂盒位置kitBoxIdList
        Map<Long, BoxPositionData> boxPositionData = getBoxPositionDataMap(result);

        return this.getKitTakeLists(result, boxPositionData);
    }

    /**
     * 从未归还清单加入归还中清单
     *
     * @param userInfo
     * @param items
     */
    public void addToReturning(UserInfoVo userInfo, List<KitUsageReturn> items) {

        Assert.isTrue(userInfo != null && !CollectionUtils.isEmpty(items), "参数缺失！");

        List<LabMemberPower> labMemberPowers = labMemberPowerService.selectList(userInfo.getLabId(), userInfo.getLabMemberId());
        Lab lab = labService.selectById(userInfo.getLabId());

        Date updateTime = new Date();
        List<Long> usageIds = items.stream().map(KitUsageReturn::getUsageId).distinct().collect(Collectors.toList());
        List<KitUsage> kitUsageUpdateList = new ArrayList<>();
        List<KitUsage> exits = kitUsageService.selectList(usageIds);

        //对应的取用信息归还（量大于可用量扣完为止） / 清空
        items.forEach(kitUsageReturn -> {
            Assert.isTrue(kitUsageReturn.getType() != null && kitUsageReturn.getUsageId() != null && kitUsageReturn.getUseAmount() != null, "请求参数缺失！");
            KitUsage kitUsageEx = exits.stream().filter(e -> e.getId().equals(kitUsageReturn.getUsageId())).findFirst().orElse(null);
            Assert.isTrue(kitUsageEx != null && kitUsageEx.getState().equals(KitUsageEnum.State.NOT_RETURN.getValue()), "试剂使用条目ID:" + kitUsageReturn.getUsageId() + ",并未被取用！");
            KitUsage kitUsage = MyBeanUtils.copyBean(kitUsageEx, KitUsage.class);
            ReagentInventory reagentInventory = reagentInventoryService.selectById(kitUsage.getInventoryId());

            assertInventoryBelongToLabAndLabMember(userInfo, reagentInventory, labMemberPowers, lab);
            if (kitUsageReturn.getType().equals(UsageOperationEnum.RETURN.getValue())) {
                //归还
                BigDecimal amount = reagentInventory.getAmount();
                BigDecimal useAmount = kitUsageReturn.getUseAmount();

                Assert.isTrue(useAmount.compareTo(BigDecimal.valueOf(0)) >= 0, "使用量不能为负值！");
                //归还时设置取用量
                BigDecimal last = amount.subtract(useAmount);
                BigDecimal zero = new BigDecimal(0);
                kitUsage.setUseAmount(last.compareTo(zero) < 0 ? amount : useAmount);

            } else if (kitUsageReturn.getType().equals(UsageOperationEnum.EMPTY.getValue())) {
                kitUsage.setUseAmount(reagentInventory.getAmount());
            }
            kitUsage.setState(KitUsageEnum.State.RETURNING.getValue());
            kitUsage.setUpdateTime(updateTime);
            kitUsage.setUsageTime(updateTime);
            kitUsage.setReturnType(kitUsageReturn.getType());
            kitUsageUpdateList.add(kitUsage);
        });

        if (!CollectionUtils.isEmpty(kitUsageUpdateList)) {
            kitUsageService.updateBatch(kitUsageUpdateList);
        }

    }


    /**
     * 取用开锁 （返回开锁列表，5分钟未开门，状态为变为取用TAKE）
     */
    public void sendTakingUnlockInfoToAio(List<Long> kitUsageIds, UserInfoVo userInfo) {

        Assert.isTrue(kitUsageIds != null && userInfo != null, "参数缺失！");
        Assert.isTrue(kitUsageIds.size() > 0, "kitUsageIds do not have any data");

        //使用websocket发送设备信息、取用信息给一体机
        DeviceUnlock deviceUnlock = kitUsageService.selectKitUsageDeviceUnLock(kitUsageIds.get(0));
        Map<String, Object> data = new HashMap<>();
        data.put("labMemberId", userInfo.getLabMemberId());
        data.put("labMemberName", userInfo.getName());
        data.put("deviceId", deviceUnlock.getDeviceId());
        onsProducer.sendBroadcastMessage(onsProperties.webSocketAioTopic, new OnsMessageVo(OnsMessageEnum.UNLOCK, data, deviceUnlock.getDeviceNo()));
        //创建取用定时任务 取用后5分钟未关锁
        createUnlockJob(userInfo, deviceUnlock.getDeviceId(), kitUsageIds, KitUsageEnum.State.TAKING.getValue(), 5 * 60 * 1000L);

    }

    /**
     * 取用关锁（修改取用中状态为未归还NOT_RETURN，扣除使用量，做取用记录）
     */
    public void changeToNotReturnAndDeduceInv(Long deviceId, Long labId, Long labMemberId) {

        Assert.isTrue(deviceId != null && labId != null && labMemberId != null, "参数缺失！");

        List<KitUsage> takings = kitUsageService.selectListInOneDevice(deviceId, labId, labMemberId, KitUsageEnum.State.TAKING.getValue());
        if (takings != null && takings.size() > 0) {


            List<ReagentInventory> updateIvn = new ArrayList<>();
            List<KitUsage> updates = new ArrayList<>();

            Map<Long, ReagentInventory> inventoryMap = new HashMap<>();
            Map<Long, Kit> kitMap = new HashMap<>();
            Date usageTime = new Date();

            takings.forEach(taking -> {
                Long inventoryId = taking.getInventoryId();

                //获取取用试剂的库存ReagentInventory
                ReagentInventory reagentInventory = getReagentInventoryFromMap(inventoryMap, inventoryId);
                if (reagentInventory != null) {
                    //获取Kit
                    Kit kit = getKitFromMap(kitMap, reagentInventory.getKitId());
                    Assert.notNull(kit, "试剂不存在！");

                    taking.setState(KitUsageEnum.State.NOT_RETURN.getValue());
                    taking.setTakeSuccess(BoolEnum.TRUE.getValue());
                    taking.setUpdateTime(usageTime);
                    updates.add(taking);

                    if (taking.getIsTakeMiss().equals(BoolEnum.FALSE.getValue())) {
                        BigDecimal canUse = reagentInventory.getAmount();
                        canUse = canUse.subtract(taking.getTakeAmount());
                        reagentInventory.setAmount(canUse);
                        reagentInventory.setInUse(1);
                        updateIvn.add(reagentInventory);
                    }
                }
            });
            if (updates.size() > 0) {
                kitUsageService.updateBatch(updates);
                //取用记录
                Set<Long> kitIds = updates.stream().map(KitUsage::getKitId).collect(Collectors.toSet());
                Users user = usersService.selectUser(labId, labMemberId, UserEnum.State.NORMAL.getValue());
                UserInfoVo userInfo = MyBeanUtils.copyBean(user, UserInfoVo.class);
                inventoryRecordService.add(userInfo, new ArrayList<>(kitIds), InventoryRecordEnum.TAKE);
            }
            if (updateIvn.size() > 0) {
                reagentInventoryService.updateInventoryListAmount(updateIvn);
            }
        }

        lockOperationService.changeUnlockToLock(deviceId, labId, labMemberId);
    }

    /**
     * 归还开锁（返回归还列表，5分钟未开门，状态为变为未归还NOT_RETURN）
     */
    public void sendReturningUnlockInfo(List<Long> kitUsageIds, UserInfoVo userInfo) {

        Assert.isTrue(kitUsageIds != null && userInfo != null, "参数缺失！");
        Assert.isTrue(kitUsageIds.size() > 0, "kitUsageIds do not have any data");

        //使用websocket发送设备信息、取用信息给一体机
        DeviceUnlock deviceUnlock = kitUsageService.selectKitUsageDeviceUnLock(kitUsageIds.get(0));
        Map<String, Object> data = new HashMap<>();
        data.put("labMemberId", userInfo.getLabMemberId());
        data.put("labMemberName", userInfo.getName());
        data.put("deviceId", deviceUnlock.getDeviceId());
        onsProducer.sendBroadcastMessage(onsProperties.webSocketAioTopic, new OnsMessageVo(OnsMessageEnum.UNLOCK, data, deviceUnlock.getDeviceNo()));

        //创建取用定时任务 取用后5分钟未关锁
        createUnlockJob(userInfo, deviceUnlock.getDeviceId(), kitUsageIds, KitUsageEnum.State.RETURNING.getValue(), 5 * 60 * 1000L);
    }

    //TODO
    private void createUnlockJob(UserInfoVo userInfo, Long deviceId, List<Long> kitUsageIds, Integer type, Long delayTimeMillis) {

        HardWareOperateRecord lock = hardwareOperateRecordService.selectLockByDeviceId(deviceId);

        LockOperation lockOperation = new LockOperation();
        lockOperation.setLockId(lock.getId());
        lockOperation.setDeviceId(deviceId);
        lockOperation.setOperate(LockOperationEnum.UNLOCK.getValue());
        lockOperation.setLabId(userInfo.getLabId());
        lockOperation.setLabMemberId(userInfo.getLabMemberId());
        lockOperationService.insert(lockOperation);

        JobDataMap map = new JobDataMap();
        map.put("type", type);
        map.put("items", kitUsageIds);
        map.put("operateId", lockOperation.getId());
        Date startDate = new Date(System.currentTimeMillis() + delayTimeMillis);
        String jobGroup = JobConstants.JOB_GROUP_USAGE_UNLOCK;
        String jobId = jobGroup + lockOperation.getId();
        scheduler.createJob(KitUsageJob.class, jobId, jobGroup, QuartzUtils.getCronExpr(startDate), map);

        lockOperation.setJobGroup(jobGroup);
        lockOperation.setJobName(jobId);
        lockOperationService.update(lockOperation);
    }

    /**
     * 归还关锁（修改取用中状态为已归还RETURNED，多退少补，做归还记录）
     */
    public void changeToReturnedAndReturnRemainInv(Long deviceId, Long labId, Long labMemberId) {
        Assert.isTrue(deviceId != null && labId != null && labMemberId != null, "参数缺失！");
        Users user = usersService.selectUser(labId, labMemberId, UserEnum.State.NORMAL.getValue());
        UserInfoVo userInfo = MyBeanUtils.copyBean(user, UserInfoVo.class);
        userInfo.setLabMemberId(labMemberId);

        List<KitUsage> returing = kitUsageService.selectListInOneDevice(deviceId, labId, labMemberId, KitUsageEnum.State.RETURNING.getValue());
        if (returing != null && returing.size() > 0) {


            List<Long> invIds = returing.stream().map(KitUsage::getInventoryId).distinct().collect(Collectors.toList());
            List<ReagentInventory> inventorys = reagentInventoryService.selectList(invIds, KitEnum.IsDelete.NOT.getValue());
            List<LabMemberPower> labMemberPowers = labMemberPowerService.selectList(userInfo.getLabId(), userInfo.getLabMemberId());
            Lab lab = labService.selectById(userInfo.getLabId());

            List<KitUsage> kitUsageUpdateList = new ArrayList<>();
            List<ReagentInventory> inventoryUpdateList = new ArrayList<>();
            List<Long> deleteIds = new ArrayList<>();
            List<Long> deleteSampleIds = new ArrayList<>();
            Set<Long> returnKitIds = new HashSet<>();
            Set<Long> clearKitIds = new HashSet<>();

            //对应的取用信息归还（量大于可用量扣完为止） / 清空
            Date updateTime = new Date();
            returing.forEach(kitUsageEx -> {
                KitUsage kitUsage = MyBeanUtils.copyBean(kitUsageEx, KitUsage.class);
                ReagentInventory reagentInventory = inventorys.stream().filter(e -> e.getId().equals(kitUsage.getInventoryId())).findFirst().orElse(null);
                Assert.notNull(reagentInventory, "库存不存在或已清空！");
                assertInventoryBelongToLabAndLabMember(userInfo, reagentInventory, labMemberPowers, lab);
                if (kitUsage.getReturnType().equals(UsageOperationEnum.RETURN.getValue())) {

                    //设置状态已归还
                    kitUsage.setState(KitUsageEnum.State.RETURNED.getValue());
                    kitUsage.setReturnSuccess(BoolEnum.TRUE.getValue());
                    kitUsageUpdateList.add(kitUsage);
                    //扣去用量设置余量
                    BigDecimal useAmount = kitUsage.getUseAmount();
                    BigDecimal takeAmount = kitUsage.getTakeAmount();
                    BigDecimal amount = reagentInventory.getAmount();
                    BigDecimal more = takeAmount.subtract(useAmount);

                    if (kitUsage.getIsReturnMiss().equals(BoolEnum.FALSE.getValue())) {
                        BigDecimal last = amount.add(more);
                        reagentInventory.setAmount(last.compareTo(BigDecimal.ZERO) < 0 ? BigDecimal.ZERO : last);
                        reagentInventory.setInUse(0);
                        inventoryUpdateList.add(reagentInventory);
                        returnKitIds.add(reagentInventory.getKitId());
                    }
                } else if (kitUsage.getReturnType().equals(UsageOperationEnum.EMPTY.getValue())) {
                    //设置状态已归还
                    kitUsage.setState(KitUsageEnum.State.RETURNED.getValue());
                    kitUsage.setReturnSuccess(BoolEnum.TRUE.getValue());
                    kitUsage.setUseAmount(reagentInventory.getAmount());
                    kitUsage.setUpdateTime(updateTime);
                    kitUsageUpdateList.add(kitUsage);
                    if (kitUsage.getIsReturnMiss().equals(BoolEnum.FALSE.getValue())) {
                        //清空库存
                        deleteIds.add(reagentInventory.getId());
                        clearKitIds.add(reagentInventory.getKitId());
                        //如果是样品，同类库存都没有后删除样品
                        List<ReagentInventory> inventoryList = reagentInventoryService.selectListByKitId(reagentInventory.getKitId());
                        if (inventoryList != null && inventoryList.size() == 1 && inventoryList.get(0).getId().equals(kitUsage.getInventoryId())
                                && KitEnum.Classify.SAMPLE.getValue().equals(inventoryList.get(0).getClassify())) {
                            deleteSampleIds.add(reagentInventory.getKitId());
                        }
                    }
                }
            });

            if (!CollectionUtils.isEmpty(kitUsageUpdateList)) {
                kitUsageService.updateBatch(kitUsageUpdateList);
            }
            if (!CollectionUtils.isEmpty(inventoryUpdateList)) {
                reagentInventoryService.updateInventoryListAmount(inventoryUpdateList);
            }
            if (!CollectionUtils.isEmpty(deleteIds)) {
                reagentInventoryLogic.deleteInventoryByIdList(deleteIds);
            }
            if (!CollectionUtils.isEmpty(deleteSampleIds)) {
                // 删除样品
                deleteSampleIds.forEach(sampleId -> {
                    reagentLogic.delete(sampleId, userInfo.getLabMemberId());
                });
            }
            //归还记录
            if (!CollectionUtils.isEmpty(returnKitIds)) {
                inventoryRecordService.add(userInfo, new ArrayList<>(returnKitIds), InventoryRecordEnum.RETURN);
            }
            //清空记录
            if (!CollectionUtils.isEmpty(clearKitIds)) {
                inventoryRecordService.add(userInfo, new ArrayList<>(clearKitIds), InventoryRecordEnum.EMPTY);
            }
        }

        lockOperationService.changeUnlockToLock(deviceId, labId, labMemberId);
    }


    private void createTakingReturningJob(List<Long> kitUsageIds, Integer type, Long delayTimeMillis) {
        JobDataMap map = new JobDataMap();
        map.put("type", type);
        map.put("items", kitUsageIds);

        Date startDate = new Date(System.currentTimeMillis() + delayTimeMillis);
        String jobId = null;
        String jobGroup = null;
        if (type.equals(KitUsageEnum.State.TAKING.getValue())) {
            jobGroup = JobConstants.JOB_GROUP_TAKING;
        } else if (type.equals(KitUsageEnum.State.RETURNING.getValue())) {
            jobGroup = JobConstants.JOB_GROUP_RETURNING;
        } else {
            throw new BrillilabException(ResultEnum.FAILURE, "Job类型不存在");
        }
        jobId = jobGroup + startDate.getTime();

        scheduler.createJob(KitUsageJob.class, jobId, jobGroup, QuartzUtils.getCronExpr(startDate), map);
    }


    /**
     * 24小时未开锁取用，变为TAKE状态
     *
     * @param kitUsageIds
     */
    public void changeToTake(List<Long> kitUsageIds) {
        Date updateTime = new Date();
        Assert.isTrue(kitUsageIds != null && kitUsageIds.size() > 0, "参数缺失！");
        List<KitUsage> takings = kitUsageService.selectList(kitUsageIds);
        List<KitUsage> updates = new ArrayList<>();
        takings.stream()
                .filter(kitUsage -> KitUsageEnum.State.TAKING.getValue().equals(kitUsage.getState()))
                .forEach(taking -> {
                    taking.setState(KitUsageEnum.State.TAKE.getValue());
                    taking.setUpdateTime(updateTime);
                    updates.add(taking);
                });
        if (updates.size() > 0) {
            Integer rs = kitUsageService.updateBatch(updates);
            Assert.isTrue(rs == updates.size(), "操作失败！");
        }
    }

    /**
     * 24小时未开锁归还，变为NOT_RETURN状态
     *
     * @param kitUsageIds
     */
    public void changeToNotReturn(List<Long> kitUsageIds) {
        Date updateTime = new Date();
        Assert.isTrue(kitUsageIds != null && kitUsageIds.size() > 0, "参数缺失！");
        List<KitUsage> takings = kitUsageService.selectList(kitUsageIds);
        List<KitUsage> updates = new ArrayList<>();
        takings.stream()
                .filter(kitUsage -> KitUsageEnum.State.RETURNING.getValue().equals(kitUsage.getState()))
                .forEach(returning -> {
                    returning.setState(KitUsageEnum.State.NOT_RETURN.getValue());
                    returning.setUpdateTime(updateTime);
                    updates.add(returning);
                });
        if (updates.size() > 0) {
            Integer rs = kitUsageService.updateBatch(updates);
            Assert.isTrue(rs == updates.size(), "操作失败！");
        }
    }

    /**
     * 实验步骤中取用
     *
     * @param experimentId
     * @param phaseId
     * @param stepId
     * @param labId
     * @param labMemberId
     */
    public List<ExperimentStepReagent> executeExperimentStepReagentTake(Long experimentId, Long phaseId, Long stepId, Long labId, Long labMemberId, String labMemberName) {

        Experiment experiment = experimentService.selectById(experimentId);
        Assert.notNull(experiment, "实验不存在！");
        Assert.isTrue(experiment.getLabId().equals(labId), "实验不属于该实验室！");
        Assert.isTrue(experiment.getExecutorId().equals(labMemberId), "您不是该实验的执行人，无法进行此操作！");

        ExperimentPhase phase = experimentPhaseService.selectById(phaseId);
        Assert.notNull(phase, "实验阶段不存在！");
        Assert.isTrue(phase.getExperimentId().equals(experimentId), "该阶段不属于本实验！");

        ExperimentStep step = experimentStepService.selectById(stepId);
        Assert.notNull(step, "实验步骤不存在！");
        Assert.isTrue(step.getExperimentId().equals(experimentId), "该步骤不属于本实验！");
        Assert.isTrue(step.getExperimentPhaseId().equals(phaseId), "该步骤不属于本阶段！");

        int i = kitUsageService.deleteByStepId(step.getId());

        //取出实验步骤中所需要的试剂 stepReagent experimentBill?
        List<ExperimentStepReagent> stepReagents = experimentStepReagentService.selectExperimentStepReagentList(experimentId, phaseId, stepId);

        //分出有groupId 和 无groupId
        List<ExperimentStepReagent> noGroup = stepReagents.stream().filter(e -> e.getGroupId() == null).collect(Collectors.toList());
        List<ExperimentStepReagent> hasGroup = stepReagents.stream().filter(e -> e.getGroupId() != null).collect(Collectors.toList());

        //有groupId 获取对应的reagentId,找到对应的reagent取用

        List<ReagentInventory> inventories = new ArrayList<>();
        if (hasGroup.size() > 0) {
            List<ReagentInventory> all = reagentInventoryService.selectByStepReagents(hasGroup);
            List<Long> hgReagentIds = hasGroup.stream().map(ExperimentStepReagent::getReagentId).distinct().collect(Collectors.toList());
            inventories = all.stream().filter(e -> hgReagentIds.contains(e.getReagentId()) && (e.getLabMemberId() == null || e.getLabMemberId().equals(labMemberId))).collect(Collectors.toList());
            if (inventories.size() == 0) {
                for (ReagentInventory oneInv : all) {
                    for (Long oneId : hgReagentIds) {
                        if (oneInv.getReagentId().equals(oneId) && !inventories.contains(oneInv) && (oneInv.getLabMemberId() == null || oneInv.getLabMemberId().equals(labMemberId))) {
                            inventories.add(oneInv);
                        }
                    }
                }
            }
        }

        //无groupId
        List<Long> ngReagentIds = noGroup.stream().map(ExperimentStepReagent::getReagentId).distinct().collect(Collectors.toList());
        List<ReagentInventory> ngInventories = new ArrayList<>();
        if (ngReagentIds.size() > 0) {
            ngInventories = reagentInventoryService.selectListByReagentIds(ngReagentIds)
                    .stream().filter(e -> e.getLabId().equals(labId) && (e.getLabMemberId() == null || e.getLabMemberId().equals(labMemberId))).collect(Collectors.toList());
            inventories.addAll(ngInventories);
        }

        //所有库存的KitSpec
        List<Long> kitIds = inventories.stream().map(ReagentInventory::getKitId).distinct().collect(Collectors.toList());
        List<Kit> kits = kitService.selectByIds(kitIds);
        List<KitSpec> kitSpecs = kitSpecService.selectList(kitIds);


        //Inventory按kitSize比例取 amount*(size/kitSize)
        ArrayList<KitUsage> kitUsages = new ArrayList<>();
        List<ExperimentStepReagent> update = new ArrayList<>();

        //步骤1把Bill中取用出来
        ExperimentStepReagent one = stepReagents.stream().findFirst().orElse(null);
        if (phase.getSort().equals(1) && step.getSort().equals(1) && one != null && one.getIsUsed().equals(BoolEnum.FALSE.getValue())) {
            List<ExperimentBill> bills = experimentBillService.selectList(experimentId)
                    .stream()
                    .filter(e -> e.getPhaseId() == null && e.getStepId() == null)
                    .collect(Collectors.toList());

            //所有inventory
            List<Long> billReagentIds = bills.stream().filter(e -> e.getSource().equals(ExperimentBillSourceEnum.REAGENT.getSource())).map(ExperimentBill::getSourceId).distinct().collect(Collectors.toList());
            List<ReagentInventory> billInventory = reagentInventoryService.selectByReagentIdList(billReagentIds, null)
                    .stream().filter(e -> (labMemberId.equals(e.getLabMemberId()) || e.getLabMemberId() == null) && e.getLabId().equals(labId)).collect(Collectors.toList());
            billReagentIds.forEach(billReagentId -> {
                ReagentInventory inventory = billInventory.stream().filter(e -> e.getReagentId().equals(billReagentId)).findFirst().orElse(null);
                ExperimentBill ivBill = bills.stream().filter(e -> billReagentId.equals(e.getSourceId())).findFirst().orElse(null);
                if (inventory != null && ivBill != null) {
                    BigDecimal takeAmount = BigDecimal.ZERO;
                    KitUsage kitUsage = new KitUsage();
                    kitUsage.setExperimentId(experimentId);
                    kitUsage.setLabId(labId);
                    kitUsage.setLabMemberId(labMemberId);
                    kitUsage.setLabMemberName(labMemberName);
                    kitUsage.setKitId(inventory.getKitId());
                    kitUsage.setReagentId(inventory.getReagentId());
                    kitUsage.setInventoryId(inventory.getId());
                    kitUsage.setFirstReagentTypeId(ivBill.getFirstReagentTypeId());
                    kitUsage.setReagentName(inventory.getReagentName());
                    kitUsage.setClassify(inventory.getClassify());
                    kitUsage.setTakeAmount(takeAmount.compareTo(inventory.getAmount()) <= 0 ? takeAmount : inventory.getAmount());
                    kitUsage.setState(KitUsageEnum.State.TAKE.getValue());
                    kitUsages.add(kitUsage);
                }
            });
            one.setIsUsed(BoolEnum.TRUE.getValue());
            update.add(one);
            //reagent的默认inventory ?
        }

        stepReagents.forEach(e -> e.setIsUsed(BoolEnum.FALSE.getValue()));
        inventories.forEach(inventory -> {
            KitSpec kitSpec = kitSpecs.stream().filter(ks -> ks.getId().equals(inventory.getKitSpecId())).findFirst().orElse(null);
            ExperimentStepReagent stepReagent = stepReagents.stream().filter(sr -> sr.getReagentId().equals(inventory.getReagentId())).findFirst().orElse(null);

            if (kitSpec != null && stepReagent != null && stepReagent.getAmount() != null && stepReagent.getIsUsed().equals(BoolEnum.FALSE.getValue()) && kitSpec.getSize() != null) {
                BigDecimal takeAmount = stepReagent.getAmount().multiply(kitSpec.getSize().divide(kitSpec.getKitSize(), 3, RoundingMode.HALF_UP));
                Kit kit = kits.stream().filter(e -> e.getId().equals(inventory.getKitId())).findFirst().orElse(null);
                if (kit != null && kit.getKitType().equals(KitEnum.KitType.ONE.getValue())) {
                    takeAmount = stepReagent.getAmount().multiply(BigDecimal.valueOf(kitSpec.getMultiple())).multiply(kitSpec.getSize().divide(kitSpec.getKitSize(), 3, RoundingMode.HALF_UP));
                }
                KitUsage kitUsage = new KitUsage();
                kitUsage.setExperimentId(experimentId);
                kitUsage.setExperimentPhaseId(phaseId);
                kitUsage.setExperimentPhaseSort(phase.getSort());
                kitUsage.setExperimentStepId(stepId);
                kitUsage.setExperimentStepSort(step.getSort());
                kitUsage.setLabId(labId);
                kitUsage.setLabMemberId(labMemberId);
                kitUsage.setLabMemberName(labMemberName);
                kitUsage.setKitId(inventory.getKitId());
                kitUsage.setReagentId(inventory.getReagentId());
                kitUsage.setInventoryId(inventory.getId());
                kitUsage.setFirstReagentTypeId(stepReagent.getFirstReagentTypeId());
                kitUsage.setReagentName(inventory.getReagentName());
                kitUsage.setClassify(inventory.getClassify());
                kitUsage.setTakeAmount(takeAmount.compareTo(inventory.getAmount()) <= 0 ? takeAmount : inventory.getAmount());
                kitUsage.setState(KitUsageEnum.State.TAKE.getValue());
                kitUsages.add(kitUsage);

                stepReagent.setIsUsed(BoolEnum.TRUE.getValue());

            }
        });

        //执行取用
        if (kitUsages.size() > 0) {
            Integer rs = kitUsageService.saveTakeList(kitUsages);
            Assert.isTrue(rs == kitUsages.size(), "操作失败！");
        }

        if (update.size() > 0) {
            experimentStepReagentService.updateBatch(update);
        }

        experimentStepService.startStep(stepId);

        //无库存，无法取用
        List<Long> collect = ngInventories.stream().map(ReagentInventory::getReagentId).distinct().collect(Collectors.toList());
        List<ExperimentStepReagent> rs = noGroup.stream().filter(e -> !collect.contains(e.getId())).collect(Collectors.toList());

        return rs;
    }

    /**
     * 实验中取用列表
     *
     * @param experimentId
     * @param labId
     * @param labMemberId
     * @return
     */
    public ExperimentKitUsageListVo getExperimentKitUsageListVo(Long experimentId, Long labId, Long labMemberId) {

        Experiment experiment = experimentService.selectById(experimentId);
        Assert.notNull(experiment, "实验不存在！");
        Assert.isTrue(experiment.getLabId().equals(labId), "实验不属于该实验室！");
        Assert.isTrue(experiment.getExecutorId().equals(labMemberId), "您不是该实验的执行人，无法进行此操作！");

        List<ExperimentStep> stepList = experimentStepService.getExperimentStepList(experimentId);

        List<KitUsage> usages = kitUsageService.selectListByExperimentId(experimentId);

        return getExperimentKitUsageListVo(experiment, stepList, usages);
    }

    private ExperimentKitUsageListVo getExperimentKitUsageListVo(Experiment experiment, List<ExperimentStep> stepList, List<KitUsage> usages) {
        ExperimentKitUsageListVo usageListVo = new ExperimentKitUsageListVo();
        usageListVo.setExperimentId(experiment.getId());
        usageListVo.setExperimentName(experiment.getName());
        if (usages != null && usages.size() > 0) {

            //试剂信息
            List<Long> inventoryIds = usages.stream().map(KitUsage::getInventoryId).distinct().collect(Collectors.toList());
            List<ReagentInventory> inventories = reagentInventoryService.selectList(inventoryIds, BoolEnum.FALSE.getValue());

            //分组
            List<ExperimentKitUsageStepVo> steps = new ArrayList<>();
            //phaseId排序
            List<Long> phaseIds = usages.stream().filter(e -> e.getExperimentPhaseId() != null && e.getExperimentStepId() != null).map(KitUsage::getExperimentPhaseId).sorted((e1, e2) -> e1 > e2 ? 1 : -1).distinct().collect(Collectors.toList());
            List<KitUsage> billUsages = usages.stream().filter(e -> e.getExperimentPhaseId() != null && e.getExperimentStepId() != null).collect(Collectors.toList());
            IntStream.range(0, phaseIds.size()).forEach(pIndex -> {
                List<KitUsage> phases = billUsages.stream().filter(usage -> usage.getExperimentPhaseId().equals(phaseIds.get(pIndex))).collect(Collectors.toList());
                //stepId排序
                List<Long> stepIds = phases.stream().map(KitUsage::getExperimentStepId).sorted((e1, e2) -> e1 > e2 ? 1 : -1).distinct().collect(Collectors.toList());
                List<ExperimentKitUsageStepVo> phaseStepList = IntStream.range(0, stepIds.size())
                        .mapToObj(sIndex -> getExperimentKitUsageStepVo(stepList, inventories, phases, stepIds.get(sIndex), pIndex, sIndex))
                        .filter(Objects::nonNull).collect(Collectors.toList());
                steps.addAll(phaseStepList);
            });

            //noStep
            List<KitUsage> noStepUsage = usages.stream().filter(usage -> usage.getExperimentStepId() == null).collect(Collectors.toList());
            List<ExperimentKitUsageVo> noStep = getExperimentKitUsageVoList(inventories, noStepUsage);

            usageListVo.setSteps(steps);
            usageListVo.setNoStep(noStep);

        }
        return usageListVo;
    }

    private ExperimentKitUsageStepVo getExperimentKitUsageStepVo(List<ExperimentStep> stepList, List<ReagentInventory> inventories, List<KitUsage> phases, Long stepId, Integer phaseIndex, Integer stepIndex) {
        phaseIndex += 1;
        stepIndex += 1;
        List<KitUsage> collect = phases.stream().filter(usage -> usage.getExperimentStepId().equals(stepId)).collect(Collectors.toList());
        if (collect != null && collect.size() > 0) {
            ExperimentStep thisStep = stepList.stream().filter(step -> step.getId().equals(stepId)).findFirst().orElse(null);
            boolean isAllReturned = collect.stream().allMatch(e -> e.getState().equals(KitUsageEnum.State.RETURNED.getValue()));
            ExperimentKitUsageStepVo usageListVo = new ExperimentKitUsageStepVo();
            usageListVo.setPhaseId(collect.get(0).getExperimentPhaseId());
            usageListVo.setPhaseSort(collect.get(0).getExperimentPhaseSort());
            usageListVo.setStepId(collect.get(0).getExperimentStepId());
            usageListVo.setStepSort(collect.get(0).getExperimentStepSort());
            usageListVo.setStepSerial(phaseIndex + "." + stepIndex);
            usageListVo.setStepContent(thisStep != null ? thisStep.getContent() : "");
            usageListVo.setAllReturned(isAllReturned);
            //转为ExperimentKitUsageVo
            List<ExperimentKitUsageVo> usageVos = getExperimentKitUsageVoList(inventories, collect);
            usageListVo.setItems(usageVos);
            return usageListVo;
        }
        return null;
    }

    private List<ExperimentKitUsageVo> getExperimentKitUsageVoList(List<ReagentInventory> inventories, List<KitUsage> collect) {
        Map<Integer, String> unitMap = dictService.getUnitMap();
        return collect.stream().map(usage -> {
            ReagentInventory inventory = inventories.stream().filter(i -> i.getId().equals(usage.getInventoryId())).findFirst().orElse(null);
            if (inventory != null) {
                ExperimentKitUsageVo kitUsageVo = new ExperimentKitUsageVo();
                kitUsageVo.setUsageId(usage.getId());
                kitUsageVo.setReagentName(usage.getReagentName());
                kitUsageVo.setFirstReagentTypeId(usage.getFirstReagentTypeId());
                kitUsageVo.setAmount(inventory.getAmount());
                kitUsageVo.setTakeAmount(usage.getTakeAmount());
                kitUsageVo.setTotalAmount(kitUsageVo.getAmount().add(kitUsageVo.getTakeAmount()));
                kitUsageVo.setState(usage.getState());
                kitUsageVo.setClassify(usage.getClassify());
                if (KitEnum.Classify.SAMPLE.getValue().equals(inventory.getClassify())) {
                    kitUsageVo.setKitType(2);
                } else {
                    kitUsageVo.setKitType(inventory.getKitType());
                }
                kitUsageVo.setUnit(unitMap.get(inventory.getUnit()));
                return kitUsageVo;
            }
            return null;
        }).filter(Objects::nonNull).collect(Collectors.toList());
    }

    /**
     * 打印预览
     *
     * @param usages
     * @param userInfo
     * @return
     */
    public PrintPreviewVo getPrintPreviewList(List<PrintPreviewGet> usages, UserInfoVo userInfo) {

        usages.forEach(e -> {
            Assert.isTrue(e.getUsageId() != null && e.getOperation() != null, "请求参数缺失！");
        });

        List<Long> usageIds = usages.stream().map(PrintPreviewGet::getUsageId).distinct().collect(Collectors.toList());

        List<KitUsageVo> kitUsageVos = kitUsageService.getKitUsageVoList(usageIds);

        List<KitUsageDevicePrintVo> kitUsageDevicePrintVoList = getKitUsageDevicePrintVoList(kitUsageVos, usages);

        PrintPreviewVo printPreviewVo = new PrintPreviewVo();
        printPreviewVo.setUsageTime(new Date());
        printPreviewVo.setUserName(userInfo.getName());
        printPreviewVo.setItems(kitUsageDevicePrintVoList);
        if (kitUsageVos.size() > 0) {
            printPreviewVo.setTakeCount(usages.stream().filter(e -> e.getOperation().equals(UsageOperationEnum.USE.getValue())).count());
            printPreviewVo.setReturnCount(usages.stream().filter(e -> e.getOperation().equals(UsageOperationEnum.RETURN.getValue())).count());
        }

        return printPreviewVo;
    }


    /**
     * 删除试剂打印预览
     *
     * @param kitId
     * @param userInfo
     * @return
     */
    public PrintPreviewVo getInventoryPrintPreviewList(Long kitId, UserInfoVo userInfo) {

        List<ReagentInventory> inventories = reagentInventoryService.selectListByKitId(kitId);

        List<KitUsageDevicePrintVo> kitUsageDevicePrintVoList = getInventoryDevicePrintVoList(inventories);

        PrintPreviewVo printPreviewVo = new PrintPreviewVo();
        printPreviewVo.setUsageTime(new Date());
        printPreviewVo.setUserName(userInfo.getName());
        printPreviewVo.setTakeCount(Long.valueOf(inventories.size()));
        printPreviewVo.setReturnCount(0L);
        printPreviewVo.setItems(kitUsageDevicePrintVoList);

        return printPreviewVo;
    }

    private List<KitUsageDevicePrintVo> getInventoryDevicePrintVoList(List<ReagentInventory> inventories) {

        Map<Integer, String> zoneMap = dictService.getZoneMap();

        //KitUsageDevicePrintVoList
        List<KitUsageDevicePrintVo> KitUsageDevicePrintVoList = new ArrayList<>();

        List<Long> roomIds = inventories.stream().map(ReagentInventory::getRoomId).distinct().collect(Collectors.toList());
        roomIds.stream().map(roomId -> inventories.stream().filter(e -> e.getRoomId().equals(roomId)).collect(Collectors.toList())).forEach(roomItems -> {
            List<Long> deviceIds = roomItems.stream().map(ReagentInventory::getDeviceId).distinct().collect(Collectors.toList());
            deviceIds.forEach(deviceId -> {
                KitUsageDevicePrintVo kitUsageDevicePrintVo = new KitUsageDevicePrintVo();
                List<ReagentInventory> deviceItems = roomItems.stream().filter(inventory -> inventory.getDeviceId().equals(deviceId)).sorted((e1, e2) -> e1.getId() > e2.getId() ? -1 : 1).collect(Collectors.toList());
                //kitUsageItemPrintVoList
                List<KitUsageItemPrintVo> kitUsageItemPrintVoList = deviceItems.stream().map(inventory -> {
                    //KitUsageItemPrintVo
                    KitUsageItemPrintVo kitUsageItemPrintVo = new KitUsageItemPrintVo();
                    kitUsageItemPrintVo.setReagentName(inventory.getReagentName());
                    kitUsageItemPrintVo.setLocation(getLocationStr(inventory));
                    kitUsageItemPrintVo.setOperation(UsageOperationEnum.USE.getValue());
                    kitUsageItemPrintVo.setInventoryId(inventory.getId());
                    return kitUsageItemPrintVo;
                }).collect(Collectors.toList());

                ReagentInventory one = deviceItems.get(0);
                kitUsageDevicePrintVo.setDevice(one.getRoomName() + " -> " + one.getDeviceIndex() + "[" + zoneMap.get(one.getZone()) + "]");
                kitUsageDevicePrintVo.setDeviceId(deviceId);
                kitUsageDevicePrintVo.setItems(kitUsageItemPrintVoList);
                KitUsageDevicePrintVoList.add(kitUsageDevicePrintVo);
            });
        });

        return KitUsageDevicePrintVoList;
    }

    /**
     * 试剂可选位置清单
     *
     * @param inventoryId
     * @param labId
     * @param labMemberId
     * @return
     */
    public List<InventoryChooseVo> getInventoryChooseList(Long inventoryId, Long labId, Long labMemberId) {

        ReagentInventory inventory = reagentInventoryService.selectById(inventoryId);
        Assert.notNull(inventory, "试剂库存不存在！");

        //同group的库存
        List<ReagentInventory> inventories = reagentInventoryService.selectListByReagentId(inventory.getReagentId());
        //权限
        if (!labMemberService.isOwner(labId, labMemberId) && !labMemberPowerService.isPower(labId, labMemberId, LabMemberPowerEnum.Power.REAGENT)) {
            inventories = inventories.stream()
                    .filter(e -> e.getLabId().equals(labId)
                            && (labMemberId.equals(e.getLabMemberId()) || e.getLabMemberId() == null))
                    .collect(Collectors.toList());
        }


        return getInventoryChooseVoList(inventories);
    }

    private List<InventoryChooseVo> getInventoryChooseVoList(List<ReagentInventory> inventories) {
        Map<Integer, String> unitMap = dictService.getUnitMap();
        Map<Integer, String> zoneMap = dictService.getZoneMap();
        Map<Long, BoxPositionData> boxPositionDataMap = getBoxPositionDataMapOfInventories(inventories);

        return inventories.stream().map(inv -> {
            InventoryChooseVo chooseVo = new InventoryChooseVo();
            chooseVo.setId(inv.getId());
            chooseVo.setAmount(inv.getAmount());
            chooseVo.setUnit(unitMap.get(inv.getUnit()));
            chooseVo.setRoomName(inv.getRoomName());
            chooseVo.setPanelName(inv.getPanelName());
            chooseVo.setDeviceIndex(inv.getDeviceIndex());
            chooseVo.setZone(zoneMap.get(inv.getZone()));
            chooseVo.setBoxColor(inv.getBoxColor());
            chooseVo.setBoxGridRow(inv.getGridRow());
            chooseVo.setBoxGridColumn(inv.getGridColumn());
            chooseVo.setKitBoxId(inv.getKitBoxId());
            chooseVo.setKitBoxName(inv.getKitBoxName());
            chooseVo.setLocation(getLocationStr(inv));
            BoxPositionData boxPositionData = boxPositionDataMap.get(inv.getKitBoxId());
            if (boxPositionData != null) {
                chooseVo.setPanelColumns(boxPositionData.getColumns());
                chooseVo.setPanelRows(boxPositionData.getRows());
                chooseVo.setGridUsedList(boxPositionData.getPanelGridUsedList());
            }
            return chooseVo;
        }).filter(Objects::nonNull).collect(Collectors.toList());
    }

    private String getLocationStr(ReagentInventory inv) {
        StringBuilder loc = new StringBuilder();
        if (inv.getPanelName() != null) {
            loc.append(inv.getPanelName()).append("平面");
        }
        if (inv.getBoxId() != null) {
            Box box = boxService.get(inv.getBoxId());
            int gridNum = box.getColumns() * box.getRows();
            if (inv.getBoxColor() != null) {
                loc.append(">").append(inv.getBoxColor()).append("盒子");
            }
            if (gridNum != 1 && inv.getGridRow() != null) {
                loc.append(">").append(inv.getGridRow());
            }
            if (gridNum != 1 && inv.getGridColumn() != null) {
                loc.append(inv.getGridColumn()).append("孔");
            }
        }
        return loc.toString();
    }

    private String getLocationStr(KitUsageVo kv) {
        StringBuilder loc = new StringBuilder();
        if (kv.getPanelName() != null) {
            loc.append(kv.getPanelName()).append("平面");
        }
        if (kv.getBoxColor() != null) {
            if (kv.getBoxColor() != null) {
                loc.append(">").append(kv.getBoxColor()).append("盒子");
            }
            if (!kv.getIsSingleBox()) {
                loc.append(">").append(kv.getBoxGridName()).append("孔");
            }

        }
        return loc.toString();
    }

    private Map<Long, BoxPositionData> getBoxPositionDataMapOfInventories(List<ReagentInventory> inventories) {
        List<Long> kitBoxIdList = inventories.stream().filter(e -> e.getKitBoxId() != null).map(ReagentInventory::getKitBoxId).distinct().collect(Collectors.toList());
        return panelLogic.getKitBoxPositionData(kitBoxIdList);
    }

    /**
     * 修改取用清单中位置信息
     *
     * @param usageId
     * @param inventoryId
     * @param labId
     * @param labMemberId
     * @return
     */
    public KitUsageItemPrintVo changeUsageInventory(Long usageId, Long inventoryId, Long labId, Long labMemberId) {

        KitUsage kitUsage = kitUsageService.selectOne(usageId);
        Assert.notNull(kitUsage, "取用不存在！");
        Assert.isTrue(kitUsage.getLabId().equals(labId), "取用不属于该实验室！");
        Assert.isTrue(kitUsage.getLabMemberId().equals(labMemberId), "取用不属于该实验室！");

        ReagentInventory inventory = reagentInventoryService.selectById(inventoryId);
        Assert.notNull(inventory, "库存不存在！");
        Assert.isTrue(inventory.getLabId().equals(labId), "库存不属于该实验室！");
        if (!labMemberService.isOwner(labId, labMemberId) && !labMemberPowerService.isPower(labId, labMemberId, LabMemberPowerEnum.Power.REAGENT)) {
            Assert.isTrue(labMemberId.equals(inventory.getLabMemberId()) || inventory.getLabMemberId() == null, "库存不属于该实验室成员！");
        }

        ReagentInventory old = reagentInventoryService.selectById(kitUsage.getInventoryId());
        Assert.isTrue(inventory.getReagentId().equals(old.getReagentId()), "非同成分试剂库存！");

        kitUsage.setInventoryId(inventoryId);
        kitUsage.setUpdateTime(new Date());
        kitUsageService.update(kitUsage);

        KitUsageVo kitUsageVo = kitUsageService.getKitUsageVo(kitUsage.getId());

        KitUsageItemPrintVo kitUsageItemPrintVo = new KitUsageItemPrintVo();
        kitUsageItemPrintVo.setLocation(getLocationStr(kitUsageVo));
        kitUsageItemPrintVo.setUsageId(kitUsageVo.getId());
        kitUsageItemPrintVo.setReagentName(kitUsageVo.getReagentName());
        kitUsageItemPrintVo.setInventoryId(kitUsageVo.getInventoryId());

        return kitUsageItemPrintVo;
    }

    /**
     * 清单数量
     *
     * @param labId
     * @param labMemberId
     * @return
     */
    public int getTakingListCount(Long labId, Long labMemberId) {

        int take = kitUsageService.selectCount(labId, labMemberId, KitUsageEnum.State.TAKE.getValue(), KitUsageEnum.State.NOT_RETURN.getValue());

        int experiment = kitUsageService.selectExperimentUsageCount(labId, labMemberId, null, KitUsageEnum.State.TAKE.getValue(), KitUsageEnum.State.NOT_RETURN.getValue());

        return take + experiment;
    }

    /**
     * 实验清单数量
     *
     * @param labId
     * @param labMemberId
     * @param experimentId
     * @return
     */
    public int getExperimentListCount(Long labId, Long labMemberId, Long experimentId) {
        return kitUsageService.selectExperimentUsageCount(labId, labMemberId, experimentId, KitUsageEnum.State.TAKE.getValue(), KitUsageEnum.State.NOT_RETURN.getValue(), KitUsageEnum.State.RETURNED.getValue());
    }

    /**
     * 取用归还中列表
     *
     * @param labId
     * @param labMemberId
     * @return
     */
    public List<KitTakeDeviceList> getTakingAndReturningList(Long labId, Long labMemberId) {
        Assert.isTrue(labId != null && labMemberId != null, "参数缺失！");

        //生成KitUsageVoList
        List<KitUsageVo> result = kitUsageService.getKitUsageVoList(labId, labMemberId, KitUsageEnum.State.TAKING.getValue(), KitUsageEnum.State.RETURNING.getValue());
        List<KitUsageVo> takeNotSuccess = kitUsageService.getKitUsageVoList(labId, labMemberId, KitUsageEnum.State.NOT_RETURN.getValue())
                .stream().filter(e -> e.getTakeSuccess().equals(BoolEnum.FALSE.getValue())).collect(Collectors.toList());
        List<KitUsageVo> returnNotSuccess = kitUsageService.getKitUsageVoList(labId, labMemberId, KitUsageEnum.State.RETURNED.getValue())
                .stream().filter(e -> e.getReturnSuccess().equals(BoolEnum.FALSE.getValue())).collect(Collectors.toList());
        result.addAll(takeNotSuccess);
        result.addAll(returnNotSuccess);

        //试剂盒位置kitBoxIdList
        Map<Long, BoxPositionData> boxPositionData = getBoxPositionDataMap(result);

        List<KitTakeDeviceList> kitTakeLists = this.getKitTakeLists(result, boxPositionData);

        for (KitTakeDeviceList kitTakeDeviceList : kitTakeLists) {

            HardWareOperateRecord lock = hardwareOperateRecordService.selectLockByDeviceId(kitTakeDeviceList.getDeviceId());
            if (lock != null) {
                LockOperation lockOperation = lockOperationService.selectUsageOperation(kitTakeDeviceList.getDeviceId(), labMemberId, LockOperationEnum.UNLOCK.getValue());
                if (lockOperation != null && lockOperation.getOperate().equals(LockOperationEnum.UNLOCK.getValue())) {
                    Date nextFireTime = scheduler.getNextFireTime(lockOperation.getJobName(), lockOperation.getJobGroup());
                    long time;
                    if (nextFireTime != null) {
                        time = nextFireTime.getTime() - System.currentTimeMillis();
                    } else {
                        time = 0L;
                    }
                    kitTakeDeviceList.setTime(time);
                    if (time < 1000) {
                        kitTakeDeviceList.setLockerState(LockStateEnum.END.getValue());
                    } else {
                        kitTakeDeviceList.setLockerState(LockStateEnum.UNLOCK.getValue());
                    }
                } else {
                    kitTakeDeviceList.setTime(5 * 60 * 1000L);
                    kitTakeDeviceList.setLockerState(LockStateEnum.LOCK.getValue());
                }
            } else {
                kitTakeDeviceList.setTime(5 * 60 * 1000L);
                kitTakeDeviceList.setLockerState(LockStateEnum.NULL.getValue());
            }
        }

        return kitTakeLists;
    }

    /**
     * 使用历史
     *
     * @param labId
     * @param labMemberId
     * @param pageNum
     * @param pageSize
     * @return
     */
    public PageVo<KitUsageVo> getUsageHistoryPage(Long labId, Long labMemberId, Integer pageNum, Integer pageSize) {

        PageVo<KitUsageVo> kitUsageVoPage = kitUsageService.getHistoryKitUsageVoPage(labId, labMemberId, pageNum, pageSize);

        List<KitUsageVo> content = kitUsageVoPage.getContent();

        Map<Long, BoxPositionData> boxPositionDataMap = getBoxPositionDataMap(content);

        content.forEach(one -> {
            //missing 判断是否可用漏取漏还
            Date usageTime = one.getUsageTime();
            Date returnTime = one.getReturnTime();
            if (usageTime != null && returnTime == null) {
                one.setIsMissing(System.currentTimeMillis() - usageTime.getTime() < 24 * 60 * 60 * 1000L);
            } else if (usageTime != null && returnTime != null) {
                one.setIsMissing(System.currentTimeMillis() - returnTime.getTime() < 24 * 60 * 60 * 1000L);
            } else {
                one.setIsMissing(false);
            }
            if (one.getState().equals(KitUsageEnum.State.NOT_RETURN.getValue()) && one.getIsTakeMiss().equals(BoolEnum.TRUE.getValue())) {
                one.setIsMissing(false);
            }
            if (one.getState().equals(KitUsageEnum.State.TAKING.getValue()) && one.getIsTakeMiss().equals(BoolEnum.TRUE.getValue())) {
                one.setIsMissing(false);
            }
            if (one.getState().equals(KitUsageEnum.State.RETURNED.getValue()) && one.getIsReturnMiss().equals(BoolEnum.TRUE.getValue())) {
                one.setIsMissing(false);
            }
            if (one.getState().equals(KitUsageEnum.State.RETURNING.getValue()) && one.getIsReturnMiss().equals(BoolEnum.TRUE.getValue())) {
                one.setIsMissing(false);
            }
            //position
            if (one.getKitBoxId() != null) {
                BoxPositionData bpd = boxPositionDataMap.get(one.getKitBoxId());
                if (bpd != null) {
                    one.setPanelColumns(bpd.getColumns());
                    one.setPanelRows(bpd.getRows());
                    one.setGridUsedList(bpd.getPanelGridUsedList());
                }
            }
        });

        kitUsageVoPage.setContent(content);

        return kitUsageVoPage;
    }

    /**
     * 漏取/漏还
     *
     * @param operates
     * @param labId
     * @param labMemberId
     */
    public void doForgetTakeOrReturn(List<KitUsageOperateVo> operates, Long labId, Long labMemberId) {
        List<Long> usageIds = operates.stream().map(KitUsageOperateVo::getUsageId).distinct().collect(Collectors.toList());
        Assert.isTrue(usageIds.size() > 0, "kitUsageIds do not have any data");

        List<KitUsage> kitUsages = kitUsageService.selectList(usageIds);
        kitUsages.forEach(e -> {
            Assert.isTrue(e.getLabId().equals(labId) && e.getLabMemberId().equals(labMemberId), "取用不属于该成员！");
        });

        List<ItemLock> itemLocks = deviceService.selectDeviceLockMapByUsageId(usageIds);

        List<KitUsage> notReturnHasLock = kitUsages.stream().filter(e ->
                e.getState().equals(KitUsageEnum.State.NOT_RETURN.getValue())
                        && itemLocks.stream().anyMatch(itemLock -> itemLock.getId().equals(e.getId()) && itemLock.getHasLock().equals(BoolEnum.TRUE.getValue()))
        ).collect(Collectors.toList());

        List<KitUsage> notReturnNoLock = kitUsages.stream().filter(e ->
                e.getState().equals(KitUsageEnum.State.NOT_RETURN.getValue())
                        && itemLocks.stream().anyMatch(itemLock -> itemLock.getId().equals(e.getId()) && itemLock.getHasLock().equals(BoolEnum.FALSE.getValue()))
        ).collect(Collectors.toList());

        List<KitUsage> returnedHasLock = kitUsages.stream().filter(e ->
                e.getState().equals(KitUsageEnum.State.RETURNED.getValue())
                        && itemLocks.stream().anyMatch(itemLock -> itemLock.getId().equals(e.getId()) && itemLock.getHasLock().equals(BoolEnum.TRUE.getValue()))
        ).collect(Collectors.toList());

        List<KitUsage> returnedNoLock = kitUsages.stream().filter(e ->
                e.getState().equals(KitUsageEnum.State.RETURNED.getValue())
                        && itemLocks.stream().anyMatch(itemLock -> itemLock.getId().equals(e.getId()) && itemLock.getHasLock().equals(BoolEnum.FALSE.getValue()))
        ).collect(Collectors.toList());

        if (notReturnHasLock.size() > 0) {
            List<Long> notReturnIds = notReturnHasLock.stream().map(KitUsage::getId).collect(Collectors.toList());
            kitUsageService.setUsageToTakeMiss(notReturnIds);
        }

        if (notReturnNoLock.size() > 0) {
            List<Long> notReturnIds = notReturnNoLock.stream().map(KitUsage::getId).collect(Collectors.toList());
            kitUsageService.setUsageToNotTakeSuccess(notReturnIds);
        }

        if (returnedHasLock.size() > 0) {
            List<Long> returnedIds = returnedHasLock.stream().map(KitUsage::getId).collect(Collectors.toList());
            kitUsageService.setUsageToReturnMiss(returnedIds);
        }

        if (returnedNoLock.size() > 0) {
            List<Long> returnedIds = returnedNoLock.stream().map(KitUsage::getId).collect(Collectors.toList());
            kitUsageService.setUsageToNotReturnSuccess(returnedIds);
        }
    }

    /**
     * 打印预览取用Kit
     *
     * @param kitId
     * @param groupId
     * @param userInfo
     * @return
     */
    public PrintPreviewVo getKitUsePrintPreviewList(Long kitId, Long groupId, BigDecimal amount, UserInfoVo userInfo) {

        Map<Integer, String> zoneMap = dictService.getZoneMap();

        //获取库存
        Date usageDate = new Date();
        List<ReagentInventory> invList = reagentInventoryService.getInventoryList(kitId, null, groupId);
        Assert.isTrue(invList != null && invList.size() > 0, "库存不存在");
        List<KitSpec> specList = kitSpecService.getKitSpecListBySpecId(invList.get(0).getKitSpecId());

        BigDecimal kitAmount = reagentInventoryLogic.getOneGroupKitAmount(kitId, groupId, null, specList);
        Assert.isTrue(kitAmount.compareTo(BigDecimal.valueOf(0)) >= 0, "Kit 可用量为0，无法取用！");

        List<KitUsageVo> kitUsageVos = new ArrayList<>();

        //根据规格循环
        specList.forEach(s -> {
            //s.getReagentId() 对应试剂需要取用的量
            BigDecimal thisSize = amount.multiply(s.getSize().divide(s.getKitSize(), 3, RoundingMode.HALF_UP));
            //s.getReagentId() 对应试剂 该次所有库存
            List<ReagentInventory> thisInvList = invList.stream().filter(i -> i.getReagentId().equals(s.getReagentId())).collect(Collectors.toList());

            Assert.isTrue(specList.size() != thisInvList.size(), "试剂存在成分未入库，无法取用！");

            //循环取量
            for (ReagentInventory inv : thisInvList) {
                if (thisSize.compareTo(BigDecimal.valueOf(0)) > 0) {
                    //可用量小于0跳过
                    if (inv.getAmount().compareTo(BigDecimal.valueOf(0)) == 0) {
                        continue;
                    }
                    KitUsageVo usage = new KitUsageVo();
                    usage.setInventoryId(inv.getId());
                    usage.setLabId(inv.getLabId());
                    usage.setLabMemberId(userInfo.getLabMemberId());
                    usage.setLabMemberName(userInfo.getName());
                    usage.setReagentName(inv.getReagentName());
                    usage.setRoomId(inv.getRoomId());
                    usage.setRoomName(inv.getRoomName());
                    usage.setBoxColor(inv.getBoxColor());
                    usage.setPanelName(inv.getPanelName());
                    usage.setBoxGridColumn(inv.getGridColumn());
                    usage.setBoxGridRow(inv.getGridRow());
                    usage.setBoxGridName(inv.getGridRow() + inv.getGridColumn());
                    usage.setDeviceIndex(inv.getDeviceIndex());
                    usage.setZone(zoneMap.get(inv.getZone()));
                    usage.setDeviceId(inv.getDeviceId());
                    kitUsageVos.add(usage);
                }
            }
        });

        List<KitUsageDevicePrintVo> kitUsageDevicePrintVoList = getKitUsageDevicePrintVoList(kitUsageVos, null);

        PrintPreviewVo printPreviewVo = new PrintPreviewVo();
        printPreviewVo.setUsageTime(new Date());
        printPreviewVo.setUserName(userInfo.getName());
        printPreviewVo.setItems(kitUsageDevicePrintVoList);

        return printPreviewVo;
    }

    /**
     * 取用归还中确认
     *
     * @param usageIds
     * @param labId
     * @param labMemberId
     * @return
     */
    public boolean operateConfirm(List<Long> usageIds, Long labId, Long labMemberId) {

        List<KitUsage> kitUsages = kitUsageService.selectList(usageIds);

        kitUsages.forEach(e -> {
            Assert.isTrue(e.getLabMemberId().equals(labMemberId) && e.getLabId().equals(labId), "取用不属于该用户！");
        });


        List<KitUsage> notReturn = kitUsages.stream().filter(e -> e.getState().equals(KitUsageEnum.State.NOT_RETURN.getValue())).collect(Collectors.toList());
        List<KitUsage> returned = kitUsages.stream().filter(e -> e.getState().equals(KitUsageEnum.State.RETURNED.getValue())).collect(Collectors.toList());
        notReturn.forEach(e -> e.setTakeSuccess(BoolEnum.TRUE.getValue()));
        returned.forEach(e -> e.setReturnSuccess(BoolEnum.TRUE.getValue()));

        notReturn.addAll(returned);

        return kitUsageService.updateBatch(notReturn) > 0;
    }

    /**
     * 指定区间内的取用次数统计
     *
     * @param kitUsageList
     * @param beginDate
     * @param endDate
     * @return
     */
    private KitUsageChartVo getUsageStatInfo(List<KitUsage> kitUsageList, Date beginDate, Date endDate) {
        KitUsageChartVo kitUsageChartVo = new KitUsageChartVo();
        kitUsageChartVo.setDateRange(DateUtil.dateString(beginDate, "M/dd") + "~" + DateUtil.dateString(DateUtil.addDate(endDate, -1), "M/dd"));
        //获取指定区间的取用数量
        List<KitUsage> statList = kitUsageList.stream().filter(p -> p.getUsageTime().getTime() >= beginDate.getTime() && p.getUsageTime().getTime() < endDate.getTime()).collect(Collectors.toList());
        kitUsageChartVo.setTakeCount(statList.size());
        return kitUsageChartVo;
    }

   

   
}
